-
-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using Keycloak/OKTA with jwt instead of sessions #9120
Comments
We don't plan to do this as there was specific reasons why it was decided to do stateful Oauth2 instead of stateless, see this twitter thread: https://twitter.com/avdev4j/status/1087652807505780736 As for the sign out problem you talk about, it should be fixed in the last 5.8 release : #8757 |
@PierreBesson I'm talking about security problems, not the logout ones. Also, if someone manages to access the token localStorage (we can also use sessionStoarge by the way) he could also access the sessionCookie, so no difference there. Any other reason? |
It seems you know what you are talking about so we should discuss this more. I'm reopening the issue. ping @mraible. |
The session cookie is sent with an httpOnly flag (if it’s not, it should be) that prevents JavaScript from being able to read it.
The problem with moving to implicit flow (besides that it’s not as secure) is that we’d have to maintain a lot more code on the client apps. Implicit flow + PKCE offers a more secure solution, but will carry the same maintenance burden on the client code.
… On Jan 26, 2019, at 04:04, Pierre Besson ***@***.***> wrote:
Reopened #9120.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@mraible even if httpOnly flag is used the attacker could send any request through my browser when using sessions, which opens to attacks like XCRF. |
@yelhouti If you want to create a pull request, I'll be happy to review the code. |
@mraible can I first create project, we agree on what is generated, then merge? |
Here's the process I typically use when modifying JHipster:
My co-worker @aaronpk submitted a new draft for OAuth 2.0 browser-based apps that recommends authorization code flow + PKCE. We don't support CORS on our |
Keycloak support CORS, they also have valid redirect URIs which might be required. |
I am very interested in this feature @yelhouti |
First I will create the POC with a monolith project (it's almost done) then I will contact you for wokring on the generator. I'll share my code with you @avdev4j very soon. feel free to talk to me on gitter so we can better organise. |
Hi, I agree with the fact that a long lived insecure session has more security implications compared to the short lived tokens. As HTTP is stateless, the protocol session was mainly used to identify the request. The OpenID connect enables the Identity, Authentication, Authorization. If OIDC is already utilized for IAM, then there is no need of using additional session handling. In-fact it may result in a more complicated architecture as well as possible security and operational issues. Session is not a good friend for the microservice architecture. To implement session management securely - https://www.owasp.org/index.php/Session_Management_Cheat_Sheet There are several implementations of SPA with PKCE https://github.com/damienbod/angular-auth-oidc-client https://github.com/IdentityModel/oidc-client-js |
Here my version with angular and keycloak: https://github.com/elhoutico/jhipster-keycloak-stateless |
@VinodAnandan @mraible or anyone, can you tell me if PKCE is needed in any other case than the one I mentionned (with iOS) to see how important it is to implement. Thanks |
@yelhouti Can you provide a brief summary of what you did to get things working? I see you're using |
@mraible keylcoak-js doesn't use storage for storing the tokens, also I'm planning to use session storage for my implementation that replaces keycloak-js to make it work with Okta and solve other problems. can you tell me how an attacker that manages to get access to my machine/browser and steal the token from storage, not able to use the cookie (I can show how the opposite is true meaning cookies are less secure). What I did is:
|
My colleague, @rdegges, wrote a post about what's wrong with using local storage, which I believe applies to session storage as well. The most common way that attackers can get access to your local storage is via 3rd party scripts. Of course, a developer probably won't add 3rd party scripts, but as soon as marketing gets involved, some might be added. For cookies, you can use an httpOnly flag to prevent JavaScript from having access to them. I think it's OK to add what you're implementing to JHipster, but I don't think it should be the default option. I think we should prompt the user to choose between authorization code flow (the current setup) and implicit flow. Then they can make the security decision themselves, and we can warn them that implicit flow is less secure. If we do add support for implicit flow, we should also enable a CSP by default that says "only scripts from this app" are allowed. |
@mraible, With all due respect to your colleague, if some javascript can be used to access storage, it can be used to send any request using the cookie without retrieving it, it might be less convenient for the attacker but for me it's the same. Also, using cookies opens you to more attacks like XSRF, where a script can execute GET requests using your cookie without even injecting malicious code, getting access to your browser or attacking the server, but only abusing the trust the server has in your browser (in his own website, the attacker can send GET requests to yours if both are open inside the same browser, and use your cookies in the process). |
That's good info @yelhouti, thanks for the link! Another thought I had today is that this is already implemented in Ionic for JHipster. When you create an Ionic project, it sets up a resource server on the JHipster side and uses implicit flow. In the next version, I'll upgrade to Ionic 4 and try adding PKCE support. Since you can use Ionic for PWAs, and it supports Angular, React, and Vue in v4, that could be an option. |
@yelhouti I think you are forgetting about the CORS and XSRF protection in JHipster
In the link you posted, it addresses this in the section notes:
Note that I'm not trained in security so others will probably know better. |
Hi, In the implicit flow, the token exchange is happening via GET requests and it will result into the token getting logged in different servers, client side, etc. An abuser who gets access to this token can easily impersonate the user. Using PKCE, the client app only receives the authorization code via the GET request and it's exchanged via a POST request with the token endpoint to obtain tokens. Even if the abuser gets the authorization code, it will be protected with PKCE (Proof Key for Code Exchange ). |
First of all guys, thank you all for your comments, I really appreciate it. |
@yelhouti My colleague, @aaronpk, proposed a new spec for OAuth 2.0 that recommends PKCE for browser-based apps. See OAuth 2.0 for Browser-Based Apps for more information. From its overview section:
|
EDIT: this comment doesn't serve any purpose anymore :) |
Hi, I will explain the other situations when the authorization code can be leaked and abused. Between a public client and an Identity Provider Server, there can be many other servers and devices ( Load balancer, Firewalls, WebServers, app servers, etc.). Most of these will log (e.g: access_log) the URL parameters including the public client (browser history).If an abuser gets the authorization_code from any of these sources, he can send it to the Identity Provider and obtain the tokens to impersonate the user. For a PKCE flow, along with the initial request, the public client will send a code_challenge/hash of the random string. And when the public client will request the tokens with an authorization code, it must provide the code_verifier (random string) otherwise the tokens won't be issued. Authorization code and refresh code is really sensitive and it needs more security. Silent renewal is a secure replacement of using refresh token SPA. All the information mentioned above can be implemented in an Angular SPA and it's explained in the following link. If you need further details, please let me know. |
@VinodAnandan authorization_code can't be used twice, and if you have SSL from your keycloak server the browser/app there is no way it can be retreived. I understand exactly how PKCE works, what I don't see is the need for it when you have HTTPS. (event query parameters are intercepted when you use HTTPS). Any way, If you guys insiste on adding PKCE, even if I don't agree I will oblige, it's 10 more lines of code, I will live :) . |
Making the /token endpoint accessible from a browser is on our roadmap, but could take 2-3 months to see in GA. AFAIK, you’ll only be able to hit it from a browser if you’re using PKCE too.
… On Feb 6, 2019, at 18:10, yelhouti ***@***.***> wrote:
I can tell you fore sure that it doesn't work because you "don't allow CORS to our token endpoint" I can see that it's a 200 but javascript can't read it because of missing CORS Header from the server. This should be fixed by Okta normally.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@mraible I'm using PKCE so no problem with that. How do you suggest we move forward then please?
|
@yelhouti : the problem is not having 4 choices, the main problem is to maintain the option once it is in the main generator-jhipster. That's the reason I proposed to implement your solution inside a blueprint:
That's why I love Vue.js blueprint and it's the perfect example what it is possible to do. So as Deepu, I think the current options are enough: JWT, session, OAuth2, UAA |
Personally I'm against a blueprint for authentication. IMO for structuring options like this one it adds more maintenance burden (always keeping up with the main generator) and a discoverability issue (people don't know about it). Also knowing the security code, it is actually only a handful of files and I think it's totally possible to maintain an additional choice. For me this Stateless OIDC option is good to have and probably will have a larger audience than the UAA solution as you can use any IdP. It would be a shame to pass on the offer of @yelhouti's contribution. |
@PierreBesson I'm definitely against adding it as an option as I already said. We have to think of our end users and the majority of them are not security experts and would be confused by seeing 2 options for OAuth. Many of them trust us to provide the right defaults and most of them believe that if we provide an OAuth option it's a good one. So I'll be more considerate of those users rather than a minority who are security experts and will know what to choose. So I stand by my decision as it will only add more maintenance(it's not just a few files, you need to take the Angular, React and now Vue clients also into account), more confusion to end users and will benefit may be few people. So for me, the benefit doesn't outweigh the complexity. Whereas building it as a blueprint or module means the maintenance burden is only on @yelhouti and not on the entire community and core team. |
@PierreBesson Unfortunately, they will be too much useless code generated in the frontend and backend, for user/role management, what I could do on the other hand, is make the UAA code easier to switch to another Idp and have a script/blueprint/module that removes/changes all the unusable code. |
@PierreBesson thanks for the info, didn't know about that, I will try it. @xetys are you ok with this approach? |
Heyo! I saw my name mentioned in this thread, in regards to a suggestion I made to not use JWTs for web authentication. I've covered this extensively in talks I've given, but I just wanted to chime in with one aspect that I didn't see discussed in this thread, but one which I think is probably the most important: if you're using JWTs for web auth, you aren't going to get any stateless benefits. Here's what I mean. Let's say that you modify JHipster to allow for users to authenticate and store a token in the browser using localStorage or sessionStorage (both of which OWASP says not to do, btw: https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Local_Storage). In this scenario, you're now opening yourself up to XSS, which is probably the most difficult type of web attack to prevent today. But ignore that for a moment, because attackers can XSS you even if you're authenticated using a sever-side session cookie, and can just make requests to your backend to accomplish stuff (albeit, it's much more difficult for them, since they can't make requests impersonating a user remotely unless the victim's browser is active). So anyway: you've got your JWT as your session token now. The problem is this: your JWT will have a timeout on it. That timeout is a variable that a developer will set to some value. For "stateless" benefits, most developers set this value to some amount of time > a few seconds, otherwise, they'd have the same old issues as typical server-side session cookies: they would need to retrieve the user's data out of some central db/cache. So you've got this JWT now, and let's say it has a 10 minute timeout. Cool. If an average user makes 10 page requests per minute, you've essentially saved yourself 100 database/cache lookups, right? Yey! But going back to the way this works, what happens if you want to revoke or change a user's permissions? Or what happens if the user updates their information? Or what happens if the user overruns their account balance and doesn't have enough money in their account to fulfill some operation? Do you have any way to log this user out? To stop them from accessing your service? The answer is "no", and that's the problem. JWTs are stateless by design, but web authentication isn't meant to be stateless. The entire point of web authentication (and web security, in general) is to guarantee consistency of sensitive data like user information. If a user is logged into your app as an admin, but then their permissions are revoked, if your server-side code is only locally validating that JWT then you're now in a compromised state. You have opened up the ability for users to do things they should not be able to. The solution, of course, is to build a centralized revocation list. Some sort of DB or cache that keeps track of all issued tokens, so that every request a user makes to your site is then validated against this central DB to make sure the token hasn't been revoked, or the user's data hasn't changed since the token was issued. But if you do this, you're now right back to square 1: everything is centralized, and your app is not stateless. Plus, you're now making the client send a larger token over the network to identify itself on every single request (because JWTs have user data embedded inside of them for statelessness), which means network requests are slower from the client to your server. All in all, I'm not a huge fan of using JWTs for web authentication. I don't see the benefit. The risk of using them is:
Hope that makes sense. |
@rdegges I see we have a fervent defender of cookies here :) . So here is why I disagree and I beleive you get benefits when using JWT:
If your access token are short lived, and you work with microservices, for each request a user does, there might multiple requests to the IdP to check the token, and revoking a refresh token is centralized any way on the IdP (with the microservices still being stateless). So my point it, yes web authentication is not really stateless (the IdP by the way has a session to allow SSO...) but client server communication should be to allow scalability... and the seconds the access token is valid is (and I think you would agree) in most cases not a problem.
So, no, we can agree that the solution is not to build a centralized system, therefore all the points you make after that I don't agree with. Now how about the benefits: well I mentioned them in my previous comments and you can find them all over the web. Also, I sincerely thank you for taking them time and giving you feedback since it allows the team to get a global view of all the pros and cons of each solution. Now this part is mainly for the Core team @deepu105 @mraible @PierreBesson @ruddell @jdubois (and sorry if I forget anyone interested):
|
Hi @rdegges, Thank you for your comments. You are not comparing the correct things, please don't isolate the JWT from the OpenID Connect context. Also, please consider a highly scalable application with microservices and multiple technology stacks, they need a common language to authenticate and authorize the user request. XSS has far more abuse cases than just stealing session ID, Tokens, etc. Happy to discuss more about XSS if needed. Also, OpenID connect delivers more security and privacy controls. I think your company (Okta) is a great believer and support for OpenID Connect. Thanks and Regards, Vinod |
Heyo! Thanks for all the responses.
This scenario was an example. This is more problematic when it relates to authorization (like what is common in OAuth/OIDC with scopes). It's more of a problem when a user authenticates and gets a token that allows them to perform some action, but then that permission is changed or removed. Then you have a security issue on your hands for the remaining duration of the token.
In this case, you are saying the same thing as me, e.g. there must be some central service that checks the user account/profile data/whatever related user info there is to validate that there is enough $$$ (or whatever data is a precious quantity) to complete a request. In all of these cases, you will have centralization and a local validation will be insufficient.
In your apps this might be true, but this is literally the exact opposite or what security means =) Authentication and authorization, by definition, will be "broken" if you cannot guarantee the consistency of your requests. To be clear: I don't think there's anything wrong with using JWTs the way you're explaining here (particularly in the context of OIDC), so long as the developers building the systems know that they are making an explicit speed vs security tradeoff. When you choose to use local validation + JWTs (like done in OIDC) you are basically shifting the burden of security correctness onto the end developer, and expect them to know/understand these complex tradeoffs in their codebases. I've worked with hundreds of companies who've built products this way and they often times have absolutely no idea that because they're using 6-hour tokens they've essentially crippled their application security model. That's why I even both mentioning this stuff: very few developers know enough (or care enough) about security to really understand these tradeoffs. I don't think it's fair to shift from a secure authn/authz system to an insecure one and put the burden on the end developer to understand :(
Noooooooooooo. As a matter of fact, refresh tokens shouldn't be used in almost any circumstance. Your IdP should be maintaining sessions instead, and you should be doing transparent redirects and token refreshes that way, vs. leaving a refresh token around which increases risk. Doing things this way still leaves you with the same problems I mentioned in my initial post: you cannot revoke user permissions, log users out, etc., because you are only relying on local validation. If your app needs the ability to do anything where permissions are being changed or removed, etc., you have to have centralization, and there are more efficient ways to do that than via JWTs. Here's the way I generally position this stuff (high level); If you don't care much about security, and want to use JWTs, use OIDC's Auth Code flow w/ PKCE. If you're building a server-to-server API, use OAuth Client Credentials. Never use refresh tokens. If you care about security, just use a traditional session cookie approach. Nothing wrong with that. It's been around forever, is well vetted, and security professionals recognize it as the best way to handle web sessions.
I wasn't separating them. I was just using those examples to simplify the context, but all of that remains true for OIDC as well. OIDC with local validation is NOT a good solution if you care about security. If you decide to use token introspection on every request, however, along with the auth code flow, then sure, do whatever you want. Ya, it is less efficient, etc., but go for it.
If you're talking about server-to-server APIs here (which most microservices would fall into), OIDC will not help you (neither will JWTs) since the spec doesn't address that. The only solution you have is:
In both of these cases, those standards are well defined, and you can use them to handle your microservice auth in a simple way. If you're building high-scale services in private networks (so your services aren't publicly exposed), I don't personally see anything wrong with going the client credentials route, and knowing that you're making a security tradeoff since you will be locally validating your tokens.
Yes! I was just highlighting the obvious things here, but I'm pretty experienced with XSS =)
Nooooo. OIDC does not deliver more security or privacy controls for first party apps. The entire reason that OAuth/OIDC was created in the first place was to handle delegated authn/authz, which is an entirely different problem. If the website you're building will be exposing user data to third parties, then by all means, use OIDC auth code flow wherever you can to make your app easier for other services to interconnect with. But if you're talking purely about building a website that handles authn/authz, there are far more secure ways to handle things. |
@rdegges I think we can agree that storing the $$$ or anything of that nature in a token is just plain stupid plus this often than by an ACID transaction in db... |
Hi @rdegges I think we have a different point of view on many things. In some cases, I may be wrong, if you could answer my following questions, it would be helpful.
|
Hi @VinodAnandan. I'll answer your questions inline.
No. There's nothing wrong with centralizing or federating identity/access management. The only insecure parts are the ones I've mentioned, e.g., using local validation only. You can do federated IAM without local validation.
I'm not really sure what you mean here by individual identity stores without security protection... Obviously, if whatever you are doing doesn't have adequate security then it will be worse than another option that is secure. To that end, centralization doesn't really matter. If the centralized solution is better, I say go with that.
No. SAML is a bad choice. There are countless ways to mess up SAML implementations purely do the XML-based nature of the standard. As a matter-of-fact, I just did a write-up on this not too long ago: https://developer.okta.com/blog/2018/02/27/a-breakdown-of-the-new-saml-authentication-bypass-vulnerability This sort of thing is pervasive over years and years.
The problem with short-lived tokens + digital signatures are:
The problem with highly sensitive apps using token introspection is purely spec related. There's nothing high-level wrong with doing token introspection on every request, except that it is less efficient than normal session cookie authentication since the end-user is going to be passing larger tokens over the network on every request, vs a small signed session ID only. This impacts user experience in low-bandwidth scenarios. If you want to know more about the spec issues/risk, you can read this excellent article: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid The problem with using something like JWTs in JHipster by default is that you're pushing more security burden onto end developers, and are expecting them to know a lot of new things in order to build a reasonably secure app. Whereas with session cookies a developer doesn't need to know anything to have a secure app, the same is not true of token-based authentication. Developers now need to know:
I'm just not a huge fan of giving end-developers that much extra work to do, especially with it relates to something that could have a very real security impact on an application. Developers are trusting y'all to do the right thing for them =)
First part: do I think that cloud IAM providers are an insecure option? I don't necessarily think so. It's probably at least as secure as doing it yourself. Let's say that you are deploying an enterprise app on AWS. Well, if you don't use a cloud-hosted IAM provider (like Okta) for IAM, and you roll it yourself, where do your users go? Into RDS? In that case, they're still sitting right there on AWS, except now you, as the developer, have a lot more work to do. In regards to my recommendation of using basic auth or client credentials: these are basically the only options for machine-to-machine authentication today. What other standards are there? You could potentially use PKI, but that is going to be a one-off and not easily understandable by most people. Regardless of whether you're using OAuth or Basic Auth for server-to-server API security, if you leak your credentials you are screwed no matter what :)
Not at all! But that functionality is ONLY POSSIBLE if you centralize your session management anyway! That is true of session cookies, JWTs, or any form of token auth. So in that scenario, the best option is to use session cookie auth regardless, since it is more secure and provides less risk.
Not at all. None of the things I said above have anything against that. |
@rdegges this is the second time you mention this point:
And I really don't understand why you are trying to make it, obviously you must know how revocation works, and it being centralized with OIdC doesn't impact performance. When a refresh token is revoked it can't be used again to retrieve an access token and in the same time, you remove all communication between the IdP and all the SPs. So what are you talking about when you are mentioning re centralizing revocation like it's a bad/un-optimized thing. Another point you are trying to make is:
Well, as matter of fact, unless you use microservices (Monolith which is the encouraged and the default) you need to manually say that you don't want cookies and in that case you are making the choice to handling your security. Sorry for the spam guys (@deepu105 @mraible @PierreBesson @ruddell @jdubois) : but what do you think of my last proposition (keeping both after fixing the security issues)? |
@yelhouti I would prefer to see this as a module first. That way, you can just support the features you’d like to without needing to make it work for React and Vue too. If your module becomes popular, we can merge it into the main generator. This also allows you to develop and release improvements at your own pace. |
Hi @rdegges , I really appreciate your reply. I am definitely interested to continue the conversation. If you prefer a private communication, you may contact me at vinod@owasp.org Do you agree that we use the session as a way to identify a user as HTTP/s is a stateless protocol? Is there any centralized session management technology which takes care of integration with multiple technologies in a microservice world, which also can be configured with different session security properties ( Idle Timeout, Absolute Timeout, Renewal Timeout, Simultaneous Session Logons, Session Revocation, etc. ) based on the security sensitivity of the application? In a microservice model, if you provide access to the data based on user identity, even if a user's access token gets compromised the attacker can only take particular user data from other microservices. A microservice doesn't have to trust any other microservices just because they are in the same network or they know some secret. When an Identity Provider issues an access token for a user, the main application/SPA/client application can carry forward the user's access token to all other microservices. To implement an effective central Identity and Access Management system, the system should have an end to end coverage. Consider a scenario where a user authenticated to an enterprise application via central IAM solution. But the application was integrated in a way that it only utilizes the central IAM solution for the initial identity establishment (login) and after that application is handling its own local session management to identify the user requests. If an attacker managed to steal the local session ID, it will be very difficult for the security team monitor the central IAM as well as the end-user to identify it and revoke the access. I believe that the developer must know how his application authentication and authorization work at least at a high level. It doesn't mean that they need to learn complete spec or implement the spec by them self. Lack of understanding may result in insecure apps with weak authentication and authorization. In order to simplify this, the OpenID foundation already provides different OpenID Connect Implementations designs for use cases and technologies ( Server side application, Single Page Application, Mobile App, etc.). OpenID foundation also provides certified and recommend implementations ( https://openid.net/developers/certified/ ). Developers just need to utilize it. @mraible , please check this library: https://github.com/IdentityModel/oidc-client-js/wiki |
Hi @yelhouti:
It definitely does impact performance. If you need to guarantee the integrity of the requestor, then you need to make a request to a centralized IdP at some point. There is no way to do that without centralization (unless you decide to broadcast your revocation list with cache invalidation to your nodes or something, which is a whole other discussion). You're talking about refresh tokens here being revoked. But again: that doesn't matter, because the problem is with the access tokens that can't be trusted for the duration of their lifetimes. If you want to configure your services such that on every request the make a token introspection request to the IdP to validate the user's identity/accuracy, then sure! Go ahead and do it =) You will not be trading speed for security in this case. But the question is: why do that? Now you've just increased the complexity and network burden of your clients for no apparent gain?
I'm not a Java developer and do not have any working knowledge of how this implementation would work. I was pulled into the thread for the security POV only, sorry.
If you are providing default values for token introspection (any value) and are not doing introspection on every request by default, then you are potentially opening up holes in your appsec model for reasons I outlined previously. |
Hi @VinodAnandan, I'll definitely shoot you an email separately. Thanks! |
Hi @rdegges, thanks for your answers, I really appreciate it. |
Another good stuff I see to not using sessions is that Kubernetes support will then be reachable ;-) |
Ok guys, this is not going anywhere so I'm gonna make an executive decision, as one of the project lead I'm in favour of not adding any new implementation to core and to keep status quo, you can ofcourse create a module/blueprint and demonstrate this so that people who are for JWT option can use it and as Matt said if it becomes popular we can reconsider additing to core. And hence I'm closing the issue but ofcourse feel free to continue the discussion as the security insights are valuable to the community. My decision is based on below facts.
Let's revisit if it becomes an issue |
Overview of the feature request
I would like to be able to use jwt instead of sessions when working keycloak.
Motivation for or Use Case
Using jwt instead of sessions has many advantages including having stateless micro-services. I don't think you guys need more convincing, since UAA is staeless.
There is a security problem with how OAuth2 is implemented today (as discussed here: #6941 (comment)), and while fixing it I would prefer to do things the right way.
Related issues or PR
It have been discussed in some comments on other issues, but I prefer having a new issue that either fixes the concern, or explain the choices to other users.
The text was updated successfully, but these errors were encountered: