Releasing Plugoid, an OpenID Connect library for Phoenix

I’m glad to release the first version of Plugoid, an OpenID Connect library for Phoenix.

This library can be useful if you delegate authentication completely to an OpenID Connect Provider.

Example configuration:

defmodule MyApp.Router do
  use MyApp, :router
  use Plugoid.RedirectURI

  pipeline :oidc_auth do
    plug Plugoid,
      issuer: "https://repentant-brief-fishingcat.gigalixirapp.com",
      client_id: "client1",
      client_config: MyApp.OpenIDConnect.Client
  end

  scope "/private", MyApp do
    pipe_through :browser
    pipe_through :oidc_auth

    get "/", PageController, :index
    post "/", PageController, :index
  end
end

More information here:

Although it’s version 0.1.0, it has a quite comprehensive support of the standard (see the README for more information). Any feedback is welcome on the issue tracker!

You can try it out with the https://github.com/tanguilp/plugoid_demo application.

For those working with OAuth2 or OpenID Connect, a few additional libraries that were needed to build Plugoid could prove useful:

Also I’ve seen that some people were looking for some project to contribute too - for those, feel free to look at the issue trackers of these libraries and contact me if you’re interested on working on an issue.

Have a good evening!

4 Likes

Congrats for your release :slight_smile:

Some questions

Do you enforce the use of state and nonce when getting the OpenID Connect Token?

Do you verify the state param in the provider callback?

Do you verify the nonce and the at_hash in the OpenID Connect token claims?

1 Like

Thanks!

State is always used, this is how we found the challenge when redirected back from the OP. Nonce is used when mandatory (implicit and hybrid flows), but can be forced with the :use_nonce option.

Depends what you mean by verify, but the state is used to match the correct OIDC challenge generated before redirecting to the OP. State is a secure random string (and not a encrypted token).

Yes, and also "c_hash". Nonce can also be checked against replay (see the :jti_register option in Plugoid.RedirectURI, the demo app uses it).

2 Likes

So this means that by default you are open to replay attacks. I enforce the use of a nonce as an encrypted token in my implementation.

In my opinion security should be opt-out not opt-in, therefore I would prefer to this parameter be used by default, and if people really want to disable it then you gaive them that option with :disable_nonce.

By verify I mean to check that was the one you sent, but it seems that you do it, once you use to match the correct OIDC, but I have not looked into your code.

I prefer encrypted tokens, because then I can check the signature and the expire time. Call me paranoid, but with hackers security is never enough.

Thats awesome :slight_smile:

Awesome that you detect replay attacks :), but its a pity that is not enforced by default as I mention above.

1 Like

Thanks for your feedback!

Not in the authorization code flow, because the authorization code can be used only once. And nonce is used in the other flows. Also, PKCE is used by default (if supported by the server) which adds another layer of defense.

Good point, I think I should add a maximum timeout for challenges.

It would be useless in the authorization code flow, and also it’s hard to setup a distributed token ID register from a library but I plan to work on this point. That said, the library defaults to the implicit flow with "form_post" response type if available at the OP (and authorization code flow otherwise). I don’t see a scenario where an attacker could access POST data without having access to browser cookies (in which case protecting against replay is meaningless) but I’ll review this choice further.

1 Like

I forgot to elaborate in the expire time, but that is for what I use it, aka to not allow a challenge to succeed after x seconds have passed.

In my lib implementation I don’t give feedback about the reason it fails, I just ask the user to retry.

Can you elaborate why you think it’s useless?

That’s what :ets and/or :mnesia are good for, and I plan to use them in my lib. Take a sneak peak to Pow to how it is done there in a distributed way.

A Man in the Middle attack is one scenario, leaked cookies to the server logs another. Anyway this cookies should have the secure and httponly flag to prevent being stolen by javascript on the page.

I work in the security space and another attack vector that is common for us to observe in the wild is that the user of your application gives away his authorization token to a third party service that will help him to take advantage of stuff is not allowed to, like earning more reward points.

EDIT:

Another attack vector are browser extensions, they have away too much power you cannot control, and the browsers extensions store are full of malicious browser extensions, and others are just tracking you and they can grab all sorts of data that you may not expect or want them to send to their tracking systems.

If you read this article from the security researcher Troy Hunt you see this:

I’ve said it before and I’ll say it again: when you install an add-on, you’re giving it an enormous amount of power over your browser. You really really want to consider which add-ons you run in Firefox (or extensions you run in Chrome) because being able to “access your data for all websites” is major. You’ll find countless stories from this year alone about add-ons and extensions going rogue, something I’ve highlighted time and time again:

So go ahead and also read the article he mentions in the quote: Malicious Chrome extensions infect 100,000-plus users, again:

Criminals infected more than 100,000 computers with browser extensions that stole login credentials, surreptitiously mined cryptocurrencies, and engaged in click fraud. The malicious extensions were hosted in Google’s official Chrome Web Store.

Or see this Tweet https://twitter.com/nikolaihampton/status/1037449795604905985:

A friend of ours wrote a reasonably popular chrome extension (~70k users). As soon as it started to take off he had offers by scammers to buy the extension. An easy way for scammers to hijack your browser: find an extension with interesting permissions, buy, push an “update”.

Or this one Hackers Extracted and Published Facebook Private Messages Grabbed Through Bad Browser Plug-Ins:

However, according to an outside expert reported by the BBC, it appears likely that at least 81,000 Facebook accounts had their privacy breached. And according to Facebook, the breach is due to malware-containing browser extensions.

1 Like

Actually, why do we need it? First thing to come to mind is bruteforce attack on the state parameter but what for…

Because when redirected back from the OP the RP receives an authorization code that can be used only once on the OP in exchange for the ID token (and optionally access token and refresh token). Once it is used on the OP, the OP deletes it and therefore it cannot be replayed. It could be intercepted in the browser URL (say, through a malicious script) but PKCE deals with that threat. So I see no replay attack scenario possible in this authorization flow.

JTIRegister library comes with an ETS implementation. As for Mnesia, it is still hard to have it working:

  • with cluster where nodes are added and removed dynamically
  • with automatic healing after a netsplit
  • from different libraries

I’d like to write such a library that would make using Mnesia as easy as ETS, but I lack time :upside_down_face:

It’s the default setting for Plugoid, plus SameSite=lax for the authentication cookie (as described in the Cookie configuration section).

That’s actually the question behind the default flow used by Plugoid (implicit with response type "id_token" and response mode "form_post"). Is there a scenario where a malicious extension could access the body of an incoming POST request, but not cookies? Because OpenID Connect is all about opening an authentication session, and an attacker wouldn’t need to steal an ID token if it could simply steal the authentication cookie.

I still have a lot to learn about OpenID Connect and all the attack vectors it may be possible, but at a first glance it looks like the mix up attack and other attacks described in this article can be of harm?

Anyway my lack of a more deep knowledge on OAuth flows doesn’t allow me to be more assertive, only cautious :wink:

Nice to know about this one :slight_smile:

For the nonce I just need to keep them around for the x amount of time I decided that the encrypted token for the nonce should be valid for, thus issues with netsplits should not a huge issue in the event of one happening. Yes it could cause some disruption, but would be in a very small window. To manage netsplits you can use unsplit or reunion that is a rewrite of unsplit.

I am using Memento, but you also have ecto3_mensia in active development.

I am not a pent tester, neither have played with browser extensions, but it looks they are given a lot of permissions by the browser to manipulate what happens in your page, thus I believe they can extract anything they want from your request(maybe except cookies), but I may be wrong. Maybe @voltone can be of help here?

Thanks again for the feedback!

I think not, as Plugoid uses automatic configuration by default. Also, the OP is hardcoded ("issuer") in the router’s pipeline configuration.

Ha, didn;t know reunion, looks interesting!

After a quick search it seems an extension can indeed read cookies on Chrome and Firefox (with some restrictions on Firefox).

1 Like

Following @Exadra37’s feedback, I’ve added protection against mix-up attacks in version 0.4.0.

It seems that a few people are using it judging by the downloads, so please feel free to share feedback about this library here, on Github, or any other place.

Have a great day!

2 Likes