The Question(s) =]
Based on my research, it seems like storing web tokens in local storage is the preferred method over using cookies in order to prevent CSRF attacks (I am aware that local storage is susceptible to XSS attacks though these seem easier to prevent than CSRF). This being said, I have been unable to locate any relavant guides on utilizing local storage for this means...
I am looking for some help on understanding how the following works...
What is the preferred method/workflow to pass a server-signed token to the browser's local storage.
Once the browser stores the token, how do I then use that stored token.
Do I need to stop the default submission of things like forms via JS and then send AJAX requests with the authorization: Bearer <token> header with every request?
When a user clicks a link to a resource owned by that user, how do I send that token to server to grant access to the protected resource?
The Tools
Front-end
HTML5 (Compiled from Handlebars)
JS
CSS (Compiled from SASS)
Back-end
nodeJS (using Express)
NOTE: I hope to edit this post with code samples in the future (once I get the hang of it lol), to help other confused people like myself in the future
Preferred method is to return token with successful response from /users/login request (wherever you prefer, header or body). Then you put it into local storage.
Most important thing here, is that JWT can NOT be used without HTTPS. Otherwise you will end up passing credentials unprotected.
After acquiring of token, you should MANUALLY add it as a header to each request. Use some js ajax wrapper to simplify this task.
There is no way as far as I know to send custom headers with <a href=""> elements. So I ended up passing additional token (some hash, not JWT) along with link <a href="/some_protectded_page?token=...">. But this is not optimal. If you render pages on server side, it is better to use sessions.
Related
I am currently working on an application (React frontend, node.js server and api) and am using JWT. I am having a hard time wrapping my head around the process of storing and sending the token using HTTP "Authorization" header.
Tutorials online seem to do a great job of showing me how to send this token once it is stored somewhere, but how does it actually get stored there in the first place is where my confusion arises.
I have two ways of thinking of approaching this:
The token is generated on login, then returned to the frontend, then stored in localstorage. Then, when a request is made, the HTTP "Authorization" header is set by pulling the token from local storage.
The token is generated on login, then returned to the frontend. It is somehow stored already in the "Authorization" HTTP header (Does this even make sense?). Then when a request is made, the header is already set.
Do option 1 but use a cookie (or session-cookie?) (don't know how to do this approach).
I would like to know:
A. Which of the 3 (if any) is the right approach
B. If approach 2 is the correct way, how do you actually STORE this header once you get the token?
C. If NOT approach 2, where is the preferred place to store this token (localstorage, cookie, etc.)?
I have tried approach 1, it works but seems unsafe and not best practice.
I have NOT tried approach 2, because I have no idea how to do it, and couldn't find anything online.
I have NOT tried approach 3, but I assume it could work in a similar fashion to 1?
First, your instincts are right; you should not use local storage for a secure token because local storage persists even when the browser is completely closed.
The most straightforward way to store your token is to just keep it in memory. A global variable in Javascript, or even attaching it to window, works fine. Then with every XHR call you insert Bearer [Token] into the Authorization header yourself. There are a bajillion npm packages to help with XHR requests but virtually all of them should let you insert this header. If you haven't already you should write a single wrapper function to encapsulate all your API calls and insert the token at this point.
The drawback with this is that the token won't persist across different pages on the same domain or across browser tabs, nor will it work with non-XHR requests like img src="https://secure_api_route_that_returns_an_image.jpg", as there's no way to programmatically inject custom headers in those cases. I don't know if any of that is a problem for you. Usually with React SPAs you aren't going to be bouncing around truly different "pages" on the same domain, but you may well want to be securely sourcing images with what are technically API routes, or keeping the session alive across browser tabs; I'm not sure what your requirements are.
Anyway if you do need any of that functionality, you have to use a "session cookie". (Technically you could use session storage if you only need to preserve the token across page navigation but it doesn't work across tabs, so I find it to be pretty useless over just storing in-memory). This just means a cookie with no expiration date, which is automatically purged when all browser tabs have been closed. You must enforce earlier expiration on the backend rather than through the cookie header.
I use .NET backends rather than Node, so I can't give you specific code, but basically you need to return this header in a successful login API response:
set-cookie: myCookie={jwt}; Path=/; Secure; HttpOnly; SameSite=Strict;
Don't omit Secure, HttpOnly or SameSite=Strict except possibly in development, as otherwise you'll be open to common vulnerabilities. (This is one of the disadvantages of the cookie approach; it's easier to implement wrongly and open up a vulnerability). This assumes your frontend and backend are hosted on the same domain. It becomes a little more complicated if not (CORS, etc.) but it can be done in that case too with a little more work.
On the authentication side, you will just need to look for this cookie in every API other than login. If everything is working right the browser will automatically send something like this with every request to your domain, on any tab, for as long as any browser tab remains open:
cookie: myCookie={jwt}
Again not a Node.js guy but I'm reasonably sure most any library that can verify a token via the Authorization header will support cookie authentication too; you'll need to check the documentation or please post a new question if you can't figure it out.
On the frontend side, besides the cross-tab support, the browser takes care of saving the cookie and sending it when it should, so it's conceptually close to what you're looking for in option 2.
So as with most things there's no single right way (though there is definitely one wrong way - localstorage). For what it's worth, a few years ago I surveyed several commercial sites to see how they handled this, and I found most used the session cookie. This included U.S. banks and financial institutions, which have to follow some of the strictest security standards that exist. While cookies sometimes get a bad rap, when used correctly they are still industry standard for secure authentication. But storing the token in plain old Javascript memory is fine if you don't want to deal with cookies or need the features cookies give you.
I’m currently reading through RFC 6749 (“The OAuth 2.0 Authorization Framework”) and RFC 6750 (“The OAuth 2.0 Authorization Framework: Bearer Token Usage”).
I wonder if there is a way to send the Authorization: Bearer ... header from a browser-based client, that automatically links the token to requests, like there is with Authorization: Basic ..., which can be triggered by sending a WWW-Authenticate: Basic realm="..." in a response. The browser then asks for a username and password and sets the Authorization header automatically in the next request.
Is there a way to do something similar for bearer tokens? Especially to link the token to a host or similar context that works across page refreshes?
The reason I’m asking is to avoid an unnecessary delay in having to load and parse some JavaScript that extracts the bearer token from – say – LocalStorage and setting the Authorization header. This would also allow me to have protected assets which are not requested via Ajax or Fetch requests, e.g. images (img tags).
I know a common workaround is to substitute the bearer token for a session cookie. But I’d like to know if there are other solutions to this problem.
ACCESS TOKEN USAGE
There are no options that will send access tokens automatically during HTML requests. They are designed to only be sent when your code explicitly requests it. This prevents certain vulnerabilities that were common with cookies.
HYBRID APPROACH
I've come to think that the best all round option for modern SPAs is to adopt the following approach:
Use access tokens in the browser - to support fast cross domain API calls
Use HTTP only cookies to handle aspects related to page reloads and multi tab browsing - where the cookie can also store or link to a refresh token
SECURING HTML ASSETS
It feels like a cookie is also the only option that will work well for your scenario. As you say, a cookie will be sent on image requests before your Javascript bundles are fully downloaded.
MY SCENARIO
I had different reasons for wanting the benefits of both cookies and tokens, to work around some token renewal problems during multi tab browsing. I wanted the overall behaviour to be that of an SPA though.
LIMITED USAGE COOKIES
In my case I used a cookie, but in a very targeted way. Perhaps in your case you could do something similar, while continuing to use access tokens for API calls.
I have a private API, where I'm using basic authentication as my security layer. Right now the API is consumed by my iOS app, so no one is able to see the key pair.
I'm creating the same app for the web now, using React and Javascript and need to consume the same API using basic authentication.
How can I use my API key pair in Javascript without exposing that key pair to the public? Is such a thing even possible?
As #Andrew mentioned, that is not possible, you can just make it harder to get, but it'll be there somewhere on the client code, and that's enough to say you're exposing it.
If you're open to alternatives, I suggest you to use a per user authentication for the first request, and then a token based authentication for further requests. That token can be a JSON Web Token and it's the flow I'm talking about:
This is the way it works, taken from JWT's official documentation:
In authentication, when the user successfully logs in using their
credentials, a JSON Web Token will be returned and must be saved
locally (typically in local storage, but cookies can be also used),
instead of the traditional approach of creating a session in the
server and returning a cookie.
Whenever the user wants to access a protected route or resource, the
user agent should send the JWT, typically in the Authorization header
using the Bearer schema. The content of the header should look like
the following:
Authorization: Bearer <token>
TL;DR: No.
If the client needs to be able to connect to the API directly, there is no surefire way to prevent them from discovering the API key, as they must, by design, be able to access it in order to send it in the request. You can take measures to obfuscate it, by storing it encoded (but the client will have to have the decoding algorithm as well).
This is in fact also true with your iOS app. Someone can reverse engineer the binary or intercept the requests and view the header, discovering the API key.
A possible “solution” is likely to have each client get their own API key, be it temporary or permanent, that is in someway locked to their account/device/session to limit reuse.
I want to create an API at www.MyDomain.com that is accessible from public websites www.Customer1.com and www.Customer2.com. These public websites display each customers inventory and do not have any login features. They will use AJAX calls to read data from my API.
How can I secure the API so that it can be accessed via AJAX from different domains but no one can access the API to be able to scrape all of my customers data and all of their inventory?
I have tried thinking of different solutions on my own but they would all either require people to login to the public websites (which isn't an option) or it would require some secret "key" to be displayed publicly in the browser source code which could then be easily stolen.
Any ideas would be greatly appreciated.
Thanks!
P.S. Are their any obstacles that I am going to run into using Javascript & CORS that I need to look into now?
Anything that is accessible without authentication from a browser is by definition insecure, so you can't stop that. Your best bet is to have to have a relationship with the owner of customer1.com and customer2.com - the server apps for those two websites would make an HTTP call to you and authenticate with your service. Going this way also avoids the CORS issues you're talking about.
If you've already designed the client functionality, you can still probably do it without much change to the javascript - have it point to customer1.com for its AJAX call instead of your API, and customer1.com would accept this request and just act as a proxy to your API. Aside from the authentication, the rest of the request and response could just be pass-throughs to your API.
You can use Microsoft.AspNet.WebApi.Cors.
It's just need add ONE line at webapi config to use CORS in ASP.NET WEB API:
config.EnableCors("*","*","*");
View this for detail.
The simplest way to provide a minimum security here is to provide some kind of token system. Each app has its own token, or combination of tokens which it must pass to the server to be verified. How you generate this tokens is up to you and other than being linked to app's access, doesn't have to mean anything.
Provide a way for each API implementer to open an account with you. This way you will know who is accessing what and in some cases you can block/stop service.
For instance, a token can just be an MD5 hash:
7f138a09169b250e9dcb378140907378
In the database, this hash is linked to their account. On each request, they send this token with what they want. It is verified first to be valid, then the request is fore filled. If the token is invalid, then you can decide how to deal with it. Either don't return anything or return an "access denied" (or anything you want).
One thing to avoid is having a single token for everyone, though this can be a starting point. The reason for this is if some unauthorized app gets a hold of this token and exploits it, you have to change the token for everyone, not just the app that somehow leaked the token. You also can't control if someone has access to something or not.
Since you listed ASP.NET, I can also point you to WCF, which is fairly complex but has all the tools that you need to setup a comprehensive web service to service both you and your clients.
I hope this gives you a starting point!
EDIT:
There are security concerns here in the case that someone leaks their token key somehow. Make sure that you setup a way in which the app/your service do not expose the the token in anyway. Also have a flexible way of blocking a token, both by your clients in you, if it so happens that a token is exploited.
I have a question regarding cross-origin policies.
I have a web app that gets data, usually in JSON format, via ajax.
When the web app initialize, a unique 'key' or 'token' is created from the server via ajax and is sent to the client, as a mean to identify it. The token is sent back on every ajax call for validation purposes. If it is not validated within two hours, a PHP script deletes it, and the user is required to authenticate him/herself again.
If the user sends another ajax call (i.e. if there is activity with the associated token), the token sets its expiration for another 2 hours.
On every call, I validate the token and then process the request. Everything works well but my issue is security-oriented.
Since the token is stored client-side (very crudely, like window.token = 'YTM0NZomIzI2OTsmIzM0NTueYQ==';), won't it be possible for malicious users to inspect the code, copy the JavaScript including the token, and create another app that will access the same data?
Since the token is stored client-side (very crudely, like window.token = 'YTM0NZomIzI2OTsmIzM0NTueYQ==';), won't it be possible for malicious users to inspect the code, copy the JavaScript including the token, and create another app that will access the same data?
Yes.
And possibly even more disturbing to you may be this: it doesn't even matter how your token is stored client-side - they'd even be able to login using the same API you expose to your users for logging in. (And if you think you don't have a login API because it's a form-post or something similar, you're fooling yourself - a form post is just as much an "API" as anything else... and can easily be replicated elsewhere).
The cross-domain stuff has very little to do with anything - as that's a client-side restriction of a browser - intended for the user's protection - not yours. I can make any HTTP request I want from a desktop or a server. I can even setup a service which allows me to proxy all requests made to my service over to your service... so the cross-domain security in browsers is of no help to you.