I've spent a couple weeks trying to wrap my head around JWT objects. The premise makes sense but where I get confused is the security aspect. If I am a Javascript Client (e.g. Firebase) and want to send a secure request to an api using Open Auth, I would encrypt my message with a key. However, since the client source may be viewed how can I secure my Key so malicious requests don't go through. Am I missing something. Is there a way to secure the key?
Joel, I think you got the directions wrong ;)
One would use JWT within the OAuth protocol to achieve what some people might call "Stateless Authentication", meaning that the auth server would issue a signed token (for e.g. a client application or a user) after successful authentication (of the client or user) without storing info about/ of it, which would be required when using opaque token.
The signed token could be used by your JS client to e.g. call a certain REST-API endpoint (on a so-called resource server) that would verify the signature of the token and authorize your request or not, based on the content (the claims) of the JWT.
Both, your client application as well as the resource server are able to introspect the token and verify its signature because they either have a shared secret with the auth server (who used the secret to sign the token in the first place) or know the public key that corresponds to the private key the auth server used to sign the token (as Florent mentioned in his comment).
JWTs can also be encrypted, which is useful if the resource server or the auth server require sensitive information but don't want to store/ access the data. You would not be able to introspect it as long as you don't have the used encryption secret.
... long story short, the OAuth protocol describes client auth against a resource or an auth server. JWT can be used to transfer auth prove (as a Bearer token within the Authorization header). However, the idea of using JWT in the OAuth flow is not to "send a secure request to an api".
The encryption process is performed using the public key of the recipient.
Your client has no private key to generate and manage.
If you want to receive and decrypt such JWT, then your client has to create a key pair (private and public) for the session only and then exchange the public key with the server.
When building an api server, I prefer the client do the encryption process on their own server, and send the encrypted data after that. Everything is under https.
If the encryption somehow must be done on the web client side, I prefer the key to be very short-lived & time based, and both the api server and client have the agreed special algorithm to generate that key again. Therefore, if the key is hacked somehow, the attacker can not benefit in long term.
Related
I am implementing a secure way for the frontend to communicate with the backend using a secret key. The backend is a sensitive service (mobile banking.)
First I was thinking JWT, but the token-based approach has two disadvantages:
a) the front-end has to obtain the token, this means it has to send some auth data to the back-end - and if the front-end can do this, anyone can do this.
b) even if there is some secure way of obtaining the token, anyone can fire up Chrome dev tools and use it while it's not expired.
So the alternative approach is to sign each request from a front-end with a secret key. The key is known to back-end and front-end the front-end is bundled and uglified so as to keep the key secret. We concatenate the request URL and its payload, encrypt them with a secret key and send the resulting hash in a header. The back-end gets the request, does the same encryption and compares the headers; if they are equal - it makes the request.
This leads me to three questions:
Does this really mean that even if the request is sniffed it cannot be reproduced unless the url+payload is the same? Is there something i'm missing?
Is there a JS library implementing this approach? (or maybe something for the backend too - I am using Django)
Is there a better approach?
Bundle as you want, if your security key which authorizes request is inside js i will be able to un-uglify (beautify) and get it. Use SSL to encrypt connection and just use JWT ;)
http://jsbeautifier.org/
You will have to authorize user somehow anyways, so it means sending private data to establish the "session". Let it be username, email, password or some "secret" token.
I've recently started using modern front end technologies like React/Angular and as a result have started using tools like JSON Server to recreate dummy restful db interactions.
My understanding is that most rest api's authenticate via some kind of token and secret that is either passed as part of the url or as a header. This seems fine for retrieving data, but is it not risky exposing these login credentials in a front end language like JS when writing is possible?
My thinking is that all it would take is a simple view source for somebody to steal my token/secret and potentially start populating my db with data.
In the problem that you describe the client (browser) has the login credentials because the server provide them. There is no "exposing" as the credentials are already exposed. Exposing your credentials to every client means that there is no security.
When we talk about security we consider as a client the browser not the real person that operates the browser. As you said, the real person can access all the browser's data.
To secure your API the secret key must be kept secret. This means that each client has a different key and uses it to get their data/services from your RESTfull server.
In a simple senario this key can be used/managed like the session id.
The client should first pass through an authorization process (login maybe) and then a temporary key can be generated for the client's session.
Generally, a key is converted to rights. If every client by default has the key, everyone has the default rights, so you may also remove the key and set the default rights to every request.
A client that you don't want to have full access to your db should have a key that gives him limited access to your db.
On the other hand, if the client provides the key, this is secure. For example a php code on a server that uses the secret key for accessing your API.
I'm exploring JWT and OAuth2 for a Javascript Single-Page-App which will make calls to a backend server-side API. I've come up with a security process that involves using two tokens and gives me the advantage of avoiding the need to have an additional server-side session storage:
The first time the client JS app is loaded up, user sends username/password over SSL to OAuth2 server. The server will set a cookie (normal cookie that is readable by client, without any HttpOnly flag set) that contains a JWT with an OAuth2 access token inside it's claims (along with some other non-confidential data in the JWT claims, ie. user's first/last name, country, role/permission). The server will also set a HttpOnly cookie that will contain the OAuth2 refresh token.
The cookies set by the server will be included on every request from the client automatically (always over SSL), so the server will receive the JWT (see step 3) and both confirm the signature and confirm the OAuth2 access token. The server will also confirm the refresh token. Since the server is checking the access token and refresh token against the OAuth2 database on each request, this gives us the ability to revoke access (which we would not be able to do with the JWT signature alone). We can do a "hard" revoke which revokes both access and refresh token. And we can do a "soft" revoke which just revokes the access token (for instances where perhaps some data that we keep in the JWT claim gets updated, ie. user changes their name or country or role). A soft revoke would be invisible to the client end user (it wouldn't disrupt their logged in status).
In step 2 above, the server will actually look for the JWT in a specific header set by the client (instead of the cookie set by the server). For example, the client JS app will read the JWT from the cookie and then set the JWT in another part of the header. By requring the client to explicitly set a header key/value containing the JWT shows that the client was able to read it's own cookie, thus preventing against XSRF (cross-site request forgery).
The HttpOnly cookie that contains the refresh token ensures we are protected against XSS (ie. some malicious javascript that sneaked its way onto our client). If our JWT was stolen, access still wouldn't be granted because the refresh token was not also seen or stolen by the JS.
With this approach we get all these benefits:
We don't need a server-side session storage. Since we are hitting an OAuth2 server then we can simply just include some extra data in the JWT that we return (non-confidential data). We wouldn't need to re-query/refresh the data in the JWT every time, but perhaps only when the OAuth token is revoked (ie. was revoked when some user data was changed that we include in the JWT's). No need to tackle the storage/scaling requirement that comes with using sessions. The client JS app can use this data like any other app would normally use sessions. For instance I can display a user's name on every "page" in the app. We could also just use websockets, but the JWT is a good backup place for adding some data if we need it.
We are protected against XSRF.
We are protected against XSS.
We can revoke access and also log users out (which is not easily possible with JWT alone).
SSL prevents man-in-the-middle attacks.
The JWT adds a little extra security hurdle for attackers to pass versus just a normal JSON object serialized in the cookie. The attacker would need to get the server-side key for signing JWT's (in addition to OAuth access). The JWT is also a standard, so easier for a trusted developer to work with.
The JWT can be easily passed down to other micro-services sitting behind the OAuth layer to use service-to-service. We can pass it around as "session like" data access to all the services on a request. If a service want's to change something in that data, then they can inform OAuth2 server and it will "soft" revoke the user's current JWT (not really much different from the process with a session storage) and provide a new one.
I haven't exactly seen anyone detail a security process like this yet. Many I see seem to only talk about using JWT with an OAuth2 access token inside and don't elaborate much more. So my question is, does this approach indeed provide the benefits I listed above? If not, what am I missing here and what security hole have I not covered for?
I'm working on a javascript application using a REST API.
Authentication is made with JWT tokens stored in cookies
Right now, this scenario is implemented:
user sign in with credentials. Client calls POST /token to authenticate
server responds with a HTTP-only cookie containing the token.
once authenticated, client makes another request to get all user data (GET /me)
I would like to make this process as fast as possible and reduce the number of server requests as much as possible. I thought about combining /token and /me calls and get token and user data in the same request.
That could be done in different ways :
in the claims of the token, but client won't be able to use it as it's in a HTTP-only cookie.
in another, non HTTP-only, cookie but that will be sent uselessly with every future request, so I don't like this solution
in the response body when server sends the cookie after authentication but I have the feeling that it goes against the REST principles as we send user data from an authentication endpoint.
Is there a way to make this process more simple while respecting standard processes and REST principles?
I personnally use Cookies as a storage, but not in HTTPonly mode. In this case, the simplest is to encode the information you need inside the token.
Are you forced to use HTTP-only cookies? Is it an option for you to change it (in fact, for that you must master the authorization server)?
Another thing : using GET to pass credentials isn't safe as you probably pass your credentials in the URL, which can be fetched from server logs. Prefer POST (and HTTPS of course).
Few pointers about JWT and their storage stategies:
Tokens vs Cookies
Where to store the tokens?
Threats of token theft
Quick background:
Full Javascript SPA AngularJS client that talks to a REstful API server. I am trying to work out the best authentication for the API Server. The client will have roles and I am not concerned if the user can see areas of the client they aren't allowed because the server should be air tight.
Authentication flow:
User Posts Username and Password to let's say /api/authenticate
If a user the server generates api token ( sha hash of fields or md5) and some other meta data determining roles to pass back in 1) post reply.
The token is stored in a session cookie (no exp, http only, ssl)
Each request after authentication takes the token in the cookie and verifies this is the user.
SSL user on server.
Questions:
Is this the best way to secure the server?
Do I need to worry about replay attacks w/ SSL? If so best way to manage this?
I tried to think of a way to do HMAC security with AngularJS but I can't store a private key on a javascript client.
I initially went the http authentication method but sending the username and password each request seems odd.
Any suggestions or examples would be appreciated.
I'm currently working on a similar situation using angularjs+node as a REST API, authenticating with HMAC.
I'm in the middle of working on this though, so my tune may change at any point. Here's what I have though. Anyone willing to poke holes in this, i welcome that as well:
User authenticates, username and password over https
Server (in my case node.js+express) sends back a temporary universal private key to authenticated users. This key is what the user will use to sign HMACs client side and is stored in LocalStorage on the browser, not a cookie (since we don't want it going back and forth on each request).
The key is stored in nodejs memory and regenerates every six hours, keeping record of the last key generated. For 10 seconds after the key changes, the server actually generates two HMACs; one with the new key, one with the old key. That way requests that are made while the key changed are still valid. If the key changed, the server sends the new one back to the client so its can flash it in LocalStorage. The key is a SHA256 of a UUID generated with node-uuid, hashed with crypto. And after typing this out, i realize this may not scale well, but anyway ...
The key is then stored in LocalStorage on the browser (the app actually spits out a your-browser-is-too-old page if LocalStorage is not supported before you can even try to login).
Then all requests beyond the initial authentication send three custom headers:
Auth-Signature: HMAC of username+time+request.body (in my case request.body is a JSON.stringify()'d representation of the request vars) signed with the locally stored key
Auth-Username: the username
X-Microtime: A unix timestamp of when the client generated its HMAC
The server then checks the X-Microtime header, and if the gap between X-Microtime and now is greater than 10 seconds, drop the request as a potential replay attack and throw back a 401.
Then the server generates is own HMAC using the same sequence as the client, Auth-Username+X-Microtime+req.body using the 6-hour private key in node memory.
If HMACs are identical, trust the request, if not, 401. And we have the Auth-Username header if we need to deal with anything user specific on the API.
All of this communication is intended to happen over HTTPS obviously.
Edit:
The key would have to be returned to the client after each successful request to keep the client up to date with the dynamic key. This is problematic since it does the same thing that a cookie does basically.
You could make the key static and never changing, but that seems less secure because the key would never expire. You could also assign a key per user, that gets returned to the client on login, but then you still have to do user lookups on each request anyway, might as well just use basic auth at that point.
Edit #2
So, after doing some testing of my own, i've decided to go with a backend proxy to my REST API still using HMAC.
Angular connects to same-domain backend, the backend runs the HMAC procedure from above, private key stored on this proxy. Having this on same domain allows us to block cors.
On successful auth, angular just gets a flag, and we store logged in state in LocalStorage. No keys, but something that identifies the user and is ok to be made public. For me, the presence of this stored value is what determines if the user is logged in. We remove the localStorage when they logout or we decide to invalidate their "session".
Subsequent calls from angular to same domain proxy contain user header. The proxy checks for user header (which can only be set by us because we've blocked cross-site access), returns 401 if not set, otherwise just forwards the request through to the API, but HMAC'd like above. API passes response back to proxy and thus back to angular.
This allows us to keep private bits out of the front end, while still allowing us to build an API that can authenticate quickly without DB calls on every request, and remain state-less. It also allows our API to serve other interfaces like a native mobile app. Mobile apps would just be bundled with the private key and run the HMAC sequence for each of their requests.