I'm looking for some clarity regarding security concerns with just JWT in our current project.
basically it is working right now like this:
User authenticates with username + password at an authentication Service
frontend gets JWT
frontend can use this JWT in the communication with the backend.
but that seems unsecure for many reasons, so we discussed this so far and had a few ideas to make it more secure:
additionally encrypt the JWT, basically make an nested JWT (JWE) and work with a blacklist on logout... but here the question remains why work with an JWT and not a stateful authentication like Shared Sessions and a Redis service
Implementing an Api-Gateway so that the frontend or User gets a Session cookie and the gateway works with JWT for backend and auth. unfortunatly i've found no implementation like this whatsoever
We just want to be kinda secure in Login/Logout AND be scaleable in the the future so that there might be X other backends.
apologies for any errors, english is not my first language and i'm happy to answer any questions regarding this.
take care.
You are right that keeping tokens on the front end has some security issues. The current best practice is to try to keep tokens out of the browser altogether. At Curity we have described one possible solution as the Token Handler pattern. It adds a bit more complexity to your system but enables you to use secure sessions on the front instead of any tokens. We have provided a few implementations of the components needed by the Token Handler, you can have a look at how to run our complete example here: https://curity.io/resources/learn/token-handler-spa-example/
As to your first idea, if you want to implement blacklisting tokens, then you're in fact implementing sessions, and you're better off with cookies and plain old HTTP sessions. JWEs protect the contents of your token but an attacker can still steal such a token and use it to call your APIs.
Related
I am mid-way of implementing oidc/pkce implicit authorization flow in my asp.net core rest web api for a public JS client.
I almost understand how this works, but I can't exacly understand what are the biggest issues with another approach - if I were to use the default cookie (or session) authentication provided by ASP Identity.
I find it hard to google this topic. Can I please ask for some hints / pointers to articles?
Plain cookie authentication is still used, even when you use token based authentication.
After the OpenIDConnect client receives the final tokens, it will by default create a classic session token that contains the user details and claims. Optionally you can also store the ID/Access/Refresh tokens inside this cookie.
The cookie is encrypted so it can't be tampered or hacked.
The benefit of using OpenIDConnect is when you have multiple clients and/or API's involved and you want a standardized way to handle this. Doing the plain cookie approach with many different services is hard to make secure.
I'm trying to build a proof of concept using Angular 5 and Symfony 4. I need the backend to be decoupled from the frontend so that I can focus on using JS entirely for the frontend and to be able to escalate to apps and other types of clients.
For this reason I'm building a RESTful API on Symfony. I've managed to send credentials from the front to the back... and that's pretty much what I've managed to do because I don't know how to proceed next.
Symfony should take the login data, somehow call a service to validate, and respond properly to the frontend. What is the most secure way of doing this? I've read a lot about JWT and how it's unfitting for this use case, and apparently OAuth2 is good only for authorization and not authentication unless you use OpenId Connect. I've read that the simplest approach is to create a session ID + a CSRF token and store it in a cookie (I don't care if this breaks statelessness, being certain that the system is secure is more important). I think the latter can be done with a bundle transparently but I don't know how to do the former.
In fact I'm entirely lost. I don't know where to begin, I've been stuck for days and the task seems just too overwhelming. I was even suggested to use Laravel instead, but I don't even know where to get started and this is legit the first time I try to implement a REST API, so it's quite daunting.
What am I supposed to do here?
EDIT: Here are some of the reasons why I'm schewing JWT for authentication.
Wanting to use JWT instead of OpenID Connect is like wanting to use a SAML assertion without the SAML protocol.1
(This one could lead me to use OpenID Connect as my solution)
Stateless JWT tokens cannot be invalidated or updated, and will introduce either size issues or security issues depending on where you store them. Stateful JWT tokens are functionally the same as session cookies, but without the battle-tested and well-reviewed implementations or client support.2
Unfortunately, an attacker can abuse this. If a server is expecting a token signed with RSA, but actually receives a token signed with HMAC, it will think the public key is actually an HMAC secret key.3
This isn't just an implementation bug, this is the result of a failed standard that shouldn't be relied on for security. If you adhere to the standard, you must process and "understand" the header. You are explicitly forbidden, by the standard, to just disregard the header that an attacker provides.4
The linked websites have more information as of why JWT is not secure.
Now I am implementing a similar task, only on the frontend Vue.js. On the backend I use Symphony 4 + API Platform. At the moment, I implement secure access to the API through JWT Authentication, this method is recommended.
Links for your topic:
https://github.com/lexik/LexikJWTAuthenticationBundle
https://gist.github.com/lologhi/7b6e475a2c03df48bcdd
https://github.com/knpuniversity/oauth2-client-bundle
If you want fast setup, then use FOSUserBundle Integration, but API Platform not recomendated his method.
Or use this method at Symfony4: -
https://symfony.com/doc/current/security/api_key_authentication.html
https://symfony.com/doc/current/security/guard_authentication.html
We currently have a stateless REST api, authenticated by JWT bearer tokens. (each of our servers trust the incoming JWT token as long as it's unexpired, load the user, and auth using the loaded user.)
We currently store the JWT token in localstorage, for development convenience. However, we're starting to implement security and defences, and we want to change our implementation. So:
We're going to send the JWT token as an HTTPonly and secure cookie (incidentally, this means that we don't have to manage it on the client side Javascript, because, well, we can't.)
We're going to include a CSRF token in our JWT response.
A couple of questions:
Introducing CSRF introduces state to our system, in that we're going to have to share this token across all our servers. While not being a stateless purist, this does bother me a little. Are there other ways of dealing with this?
Should we change the CSRF token each time? It seems like there's still 30 mins (our timeout setting) worth of vulnerability if we don't. However, if we do, does this introduce timing issues with pages that would make multiple API calls?
I am developing a REST application with its own authentication and authorization mechanism. I want to use JSON Web Tokens for authentication. Is the following a valid and safe implementation?
A REST API will be developed to accept username and password and do the authentication. The HTTP method to be used is POST so that there is no caching. Also, there will be SSL for security at the time of transit
At the time of authentication, two JWTs will be created - access token and refresh token. Refresh token will have longer validity. Both the tokens will be written in cookies, so that they are sent in every subsequent requests
On every REST API call, the tokens will be retrieved from the HTTP header. If the access token is not expired, check the privileges of the user and allow access accordingly. If the access token is expired but the refresh token is valid, recreate new access token and refresh token with new expiry dates (do all necessary checks to ensure that the user rights to authenticate are not revoked) and sent back through Cookies
Provide a logout REST API that will reset the cookie and hence subsequent API calls will be rejected until login is done.
My understanding of refresh token here is:
Due to the presence of refresh token, we can keep shorter validity period for access token and check frequently (at the expiry of access token) that the user is still authorized to login.
Please correct me if I am wrong.
A REST API will be developed to accept username and password and do
the authentication. The HTTP method to be used is POST so that there
is no caching. Also, there will be SSL for security at the time of
transit
This is the way most do it, so you're good here.
At the time of authentication, two JWTs will be created - access token
and refresh token. Refresh token will have longer validity. Both the
tokens will be written in cookies so that they are sent in every
subsequent requests
Storing the tokens in cookies I not dangerous in itself, but if you somehow get you JWT module on your server to read them from there you vulnerable to CSRF attacks where any webpage can trigger a users browser to send a form + you sites cookie to your server unless you use CSRF tokens. So generally they are stored in localStorage and "manually" added to request headers every time.
On every REST API call, the tokens will be retrieved from the HTTP
header. If the access token is not expired, check the privileges of
the user and allow access accordingly. If the access token is expired
but the refresh token is valid, recreate new access token and refresh
token with new expiry dates (do all necessary checks to ensure that
the user rights to authenticate are not revoked) and sent back through
Cookies
Apart from the cookie dangers, it seems safe.
Provide a logout REST API that will reset the cookie and hence
subsequent API calls will be rejected until login is done.
You don't even need to make an API call, you can simply just purge the cookies or the localStorage object and make sure your client doesn't break on missing tokens.
The standard for the express-jwt module expects the tokens to be in its own "Authorization: Bearer [Token]" header, which I would strongly recommend over cookies. The localStorage API is available all the way back to IE8 so you should be good.
Edit:
First, it's important to know the difference between XSS and CSRF attacks since they're often believed to be the same thing.
XSS is when users get unsafe JS running on your domain in other users browsers when that happens neither JWT in localStorage or sessions and JWT in cookies are safe. With httpOnly flag on cookies, you can't directly access them, but the browser will still send them with AJAX requests to your server. If this happens you generally out of luck. To prevent this, make sure to escape all user input if it's sent to the browser.
If you load 3rd party JS with script tags or iframes this might compromise localStorage unless you are careful, but I haven't worked enough with this to help you here.
CSRF is only when other domains are trying to send normal HTML forms to your server by getting the browser to send cookies automatically. Frameworks prevent this by inserting unique random strings as hidden fields and checking them again when it's submitted. JWT's in localStorage is safe from this since each domain gets its own separate localStorage area.
But ultimately all this depends on if your service will be using one single domain, in which case httpOnly cookies will be plenty secure and easier to set up, but if you wanna spread your service out on multiple domains like api.domain.com + app.domain.com or add a native app you're forced to store you're JWTs in localStorage or some other native storage area.
Hope this helps!
I asked this question two years back and also accepted the answer. However, based on my experience and study in the last two years, I'd like to answer this just in case someone stumbles on this thread with the same question.
The approach mentioned in the question is similar to the "Resource Owner Password Credentials" grant type of OAuth 2.0. However, I think it is better to use the "Authorization Code Grant" type instead and Cookie to store the tokens instead of browser localStorage or sessionStorage. I have detailed my reasons, implementation points, security considerations and references in this StackOverlow answer.
Like OP I been using resource owner password grant.
I learned so much from Saptarshi Basu's other answer in a different post I think anyone looking into OAuth Code Flow should take a look at it, it has outlined a very solid approach to auth SPA and resource servers. It primarily relies on your backend(resource server) to handle authentication with the auth provider as a private client.
However, I will just add that people looking at implementing authentication with SPA should also consider OAuth Code Flow with PKCE. The main goal of PKCE is to allow public client such as SPA to authenticate directly with auth provider. All PKCE adds, is that when a SPA app initiates authentication, a hashed value is sent to the auth provider when the user is authenticated. And after user authenticate with the authorization provider, it redirects the user back to SPA with that hashed value as well as authorization code. Now, for the next part where the SPA calls auth provider to exchange code for tokens, instead of providing client secret, it has to provide the key that was originally used to create the hashed value. This mechanism guarantees the code cannot be used by someone who intercepted the code, and the SPA doesnt need to store a client secret like a server-side app does.
Now the only thing I'm not certain at this point is which is technically more secure, server-side authentication using standard Code Flow without PKCE or SPA authenticating directly using PKCE? Most resources I could find online currently describes and recommends the latter . However I feel that letting a private server side client handle authentication (as Saptarshi Basu described) might still be more secure. I would love to hear his opinion on this as well.
My understanding of refresh token here is:
Due to the presence of refresh token, we can keep shorter validity period for access token and check frequently (at the expiry of access token) that the user is still authorized to login.
Please correct me if I am wrong.
Assuming you're talking about using JWT as Bearer-token in OAuth (and I would strongly advice to follow the OAuth 2.0 protocol), that's right.
With an additional auth-time (timestamp of authentication) claim in your JWT, you could even drop the second token and sent your access- as a refresh-token (the auth-server could then issue a new access-token if token is valid & auth-time within allowed range)... but sure, it's also good to follow the standard ;)
Anyway, there are certain additional aspects (that tend to get difficult or are even against the fundamental ideas of JWT) you should consider before using JWTs as refresh-token, as this basically means you introduce long-living JWT:
do you need to have something like forced user logout/ token revocation by subject (e.g. if user got identified as fraudulent)?
do you need to have something like revocation of a specific token (e.g. if a user looses a device)?
...
Dependent on your use-case you should consider all the possible implications, long-living tokens have as they usually require you to introduce some kind of state on your server-side (e.g. to allow revocation/ blacklisting). Keep in mind the beauty and security of the JWT concept lies within JWTs being short-lived.
We're developing an iOS app, where the user needs to authenticate using email+password (or mobile number). Our backend is made of a couple of microservices using Akka-Http. It needs to be fast, scalable, concurrent, and the authentication+authorization should work across our multiple services.
I'm trying to figure out which authentication method to use.
Akka-HTTP currently offers Basic Auth and a partial implementation of OAuth2.
So at first we were considering Basic authentication (too simple and not enough functionality), Oauth1 (too complex), so we moved towards OAuth-2.0 because it is sort of a standard.
Then we considered AWS Cognito because it combines Oauth-2.0 and OpenID Connect which gives the authentication mechanism that OAuth2 lacks.
http://www.thread-safe.com/2012/01/problem-with-oauth-for-authentication.html
Then we realised that OAuth2 is just for authentication using a third party - when in fact we don't need a third party authentication provider - maybe we need to do it ourselves, and using Cognito is an overkill that would create extra api calls outside our microservices...
So I read a little bit about creating our own custom auth provider, using WSSE specs:
http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html
And I also found this example using Spray, but I'm sure it's not that different from Akka-Http:
http://danielasfregola.com/2015/06/29/how-to-create-a-spray-custom-authenticator/
It looks too simplified and doesn't have token expiration...
So my question is, am I missing something? What method should I chose and where can I find examples for it?
I feel like I'm going in circles, we're gonna have to write our own custom authentication provider from scratch, which kinda doesn't make sense. After all almost everybody needs authentication and it should be a standard.
I've recently been using SoftwareMill's akka-http-session library and found it simple and easy to integrate. It has support for case class based sessions, JWTs, refresh tokens with pluggable storage, using headers and CSRF tokens as well as some nice simple directives for use in routes.
My solution for user registration has been to use Keycloak, an open source server which can handle user registration and do OIDC, OAuth2 style login. It reduces the amount of code I have to write, and the code is more secure than if it rolled it myself.
I then write my application as Scala backend that's purely a JSON API and a React/Javascript rich frontend in front of that API. In this configuration the authentication is handled completely on the front-end (and can be done in your iOS client). The front-end app redirects the user to Keycloak and when the user comes back they have a signed "JWT" token you can keep in a cookie.
That JWT token is attached to all API calls made the JSON backend as an Authorization Bearer token HTTP header. The token itself contains the users email address and is cryptographically signed by the Keycloak server.
The backend gets the JWT token in the HTTP header, extracts the email address and verifies the token is cryptographically signed by the keycloak server.
It's performing a certificate check on the keycloak server and can cache it's certificate. So it doesn't need to have roundtrips like OAuth, or any upstream calls to make.
This gives us simple, low-chance-of-failure, high speed authorisation in our JSON backend API and means we aren't putting secrets in the iOS client, or rolling too much of our own code.