I am working on deploying my Node.js app into production. We had been running into some CSRF issues but after looking deeper into the problem and learning more about CSRF attacks, I'm wondering if we even need to perform these checks.
Our API is whitelisted from our CSRF checks so our mobile apps that rely on the API can run properly (we're working on securing that currently). On the web frontend, we allow our users to register/log in and create/edit their data. We use Firebase's email/password authentication system to perform authentication (https://firebase.google.com/docs/auth/web/password-auth). As I understand it, this means we don't have to worry about CSRF attacks on registering and logging in because Firebase handles that. My question is: if we make sure our users are authenticated with Firebase on each Post route in our app, does that mean we don't have to worry about CSRF attacks?
CSRF becomes an issue when you are saving a session cookie. Firebase Auth currently persists the Auth State in web storage (localStorage/indexedDB) and are not transmitted along the requests. You are expected to run client side code to get the Firebase ID token and pass it along the request via header, or POST body, etc. On your backend, you would verify the ID token before serving restricted content or processing authenticated requests. This is why in its current form, CSRF is not a problem since Javascript is needed to get the ID token from local storage and local storage is single host origin making it not accessible from different origins.
If you plan to save the ID token in a cookie or set your own session cookie after Firebase Authentication, you should then look into guarding against CSRF attacks.
Related
I'm currently creating a custom CMS for a friend's soccer team. The architecture is as follows:
On the back-end I've an API that interacts with the database (mongoDB).
On the front-end I've an express server that serves the pages using the templating engine handlebars.
Currently I've managed to authenticate requests to the API using Passport and JWTs, which is fine for querying the API, on login I'm storing a JWT with permissions in the cookie storage within the user (it's static pages and not a SPA so I cannot access local/session storage).
My issue is that I am struggling how to implement authorization on the client end for access to the admin panel. Should I decode the JWT on the client-end and read the user role then serve the pages if the admin pages if the user is an admin or should I be sending every request to access the admin section of the front-end to the API for a verification check then serve the files.
Any help would be greatly appreciated, thank you.
I think using a token authentication approach is more suited towards making requests via XHR, rather than hard reloads. The approach you are taking seems to be more suited to a session based authentication strategy. I would use passport-local and authenticate with a user name and password. Once authenticated the user is stored server side in a session variable. You could check the role from that and redirect server side.
If you were to stick with a token you could save it in local storage and then have a script on your admin panel that would first grab the token from local storage and then make a GET request to the server with the token in the header. If the token is valid send back the data to populate the page, otherwise send back an error and redirect from the front end. To get around showing an empty admin panel while checking the validity of the token you could show a loading screen until the request completed.
Help me to understand how to implement proper security for web and mobile apps, which would be enough for my case.
What I have:
Backend. Some sort of Stateless REST API, which consumes and produces JSON text. Does not store any kind of state.
Web application. Main portal to the service functionality.
Mobile applicaiton. Provides a reduced a set of functions to users of the service
I am not going to store any state on the backend. Instead, I am going to delegate this to both mobile and web browser applications.
Now here comes the question of security. How do I properly secure that?
Since session mechanism does not really work for me, I decided to go with JWT.
In my JWT I am going to store user Id and some other information like, for instance, user's privilegies.
For mobile app, I am going to send this token as a part of a response and the app will store it inside its secure store.
Each request it will send this token as Authorization Header.
For web app, I am going to send this token via HttpOnly cookie. This token, thus, will be included in every request from the client.
The problem now is a possible CSRF-attack. To address that I thought of the following. Each user "session" will be associated with CSRF token.
Since I can't store this token on the server (remember, stateless API), I can send it as encrypted (again, with JWT) token to the client via HttpOnly cookie and non-crypted in a regular cookie.
Now, every request the web client will use non-crypted token from the cookie and send it back to the server. The server will check if this token matches from the Encrypted one which is stored in HttpOnly cookie.
Also, I am going to use different URL endpoints for web and mobile web apps. What for? In order to keep auth mechanisms described above separate - I believe this will help me to keep the service secure.
Do you think it is an OK solution? What problems do you see here?
Thanks in advance.
In general, what you described looks good and pretty standard. However, if I understand correctly, the CSRF protection is flawed.
To make sure I understand correctly: a csrf token would be stored in an encrypted httpOnly cookie, only to be sent back to the server as reference. Another cookie would have the same value but unencrypted, in a plain (non-httpOnly) cookie, and the server would compare these two. What's the point? An attacker would still be able to create a webpage to have a user make an request to your website, and both cookies would still be sent.
The reference cookie is ok to be in the httpOnly cookie for reference, but the other one should not be a cookie. It could for example be a request header value that you add to all requests. The client could receive it in a response, but not as a cookie. With jQuery in the web app, you can use the beforeSend hook to add it to all subsequent requests as a header. This way an attacker could not make valid requests from another domain.
How can you provide example for refresh node js auth token? I mean by what the parameters can I refresh auth token? For example if I can refresh it by login and password then where should I store this params for single-page app? As I understand store it in cookie is not good idea for security, localstorage is not good also because some of browsers not supported it. So maybe someone know another way for refresh token?
Cookies are a very secure storage mechanism, if used correctly. Local storage should never be used for authentication information. OWASP has a great write-up on storage security:
https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Storage_APIs
To quote the important parts:
Do not store session identifiers in local storage as the data is always accessible by JavaScript. Cookies can mitigate this risk using the httpOnly flag.
[With local storage] There is no way to restrict the visibility of an object to a specific path like with the attribute path of HTTP Cookies, every object is shared within an origin and protected with the Same Origin Policy. Avoid host multiple applications on the same origin, all of them would share the same localStorage object, use different subdomains instead.
Back to your original question: where to store the refresh token? Answer: In a HttpOnly cookie. This prevents the cookie from being stolen by XSS attacks, and it makes it very easy for your server to issue new access tokens (using the refresh token) because the server will have access to both at the same time, on the same request.
You can add another layer and encrypt the entire refresh token that is stored in the cookie.
Caution: when using cookies, you also need to protect yourself against CSRF attacks
I’ve written at length about front-end security and JWTs in these two blog posts:
Token Based Authentication for Single Page Apps (SPAs)
https://stormpath.com/blog/build-secure-user-interfaces-using-jwts/
Disclaimer : I work at Stormpath, our service gives you a secure, hosted user database with many features. Our express-stormpath module makes it very easy to get started with login and registration flows for your application. We are in the process of writing a new release, and it will be using access tokens in the way that I describe in this answer.
I created AuthToken model that contain these fields:
user_id, access_token, refresh_token, access_token_expiration
After successful user login, server side will send refresh_token and access_token to client side and store it to localstorage(cookies for old browsers).
And all subsequent requests will be sent with access_token(I use header x-access-token for $httpProvider in angular).
When token expires, client needs to send refresh_token for updating access_token, refresh_token and expiration date. Since I use sockets I can refresh access_token if it is expired in any request(for this I send z-refresh-token header also for each request) so I shouldn't send any extra request and I can keep current user request, just will return tokens via socket event after it was updated.
Hope this helps
I have a load of api endpoints that I want to protect from CSRF. I'd like to do this in a stateless way, so naturally JWT comes to mind.
The problem is, these endpoints do not require the user to be logged in.
So, my problem is, I can use JWT, but I have no way of verifying the token on the server side -- I have no logged in user I can match it to.
Is there any way JWT can be used in such cases?
CSRF is only a problem for requests where the browser implicitly authenticates the request (cookies or basic authentication). But if you do not have any authentication, any site could potentially call your API.
So if I understand you correctly, you are looking for a way to make sure that the request to your API is coming from your web application.
Take a look at the client credentials grant in OAuth 2.0. It basically issues a token to authenticate the application instead of the user.
I recently read Cookies vs Tokens for Angularjs and implemented the sign in and authentication piece to allow users to sign in from a sign in page. The app is setup to have the account module (responsible for sign in's, account registration, profile, etc) as a separate page which will redirect to the SPA for the main application.
After successful sign on the token is sent back to the sign in page client as a JWT and the sessionStorage / localStorage values are set via js. Finally the user is redirected (also via js) to the main application. The issue is since I am redirecting via js the header can not be set, which obviously fails the auth in the main app when loading the page (Since my auth middleware is higher than both static and auth api requests). If I attempt to redirect from the server after a form post rather than returning the token via JSON on success, the sessionStorage will not be set via js as described in the blog post.
I've come to a couple of ideas and wanted to get input on which if either is good for best practice.
From the server set a response authenication cookie 'http only' (all our browser requirements allow this) cookie which is read on the next request to the main application. The cookie would then be read by the server and allow the secured static assets to be served. My initial thought was setting a cookie defeats the purpose of using a Authorization header on every request since there is a time the cookie could then be read even if it's removed on the first api request.
Allow the previously mentioned static assets to load without authentication (html, css, application js) and on the first internal API request (which in the application is required almost immediately on load) which will then have access through Angular's $http interceptors to set the request Authorization header. The same interceptor can then redirect to the sign in page if a 401 is sent back.
I thought the second would be a simpler approach due to only needing to move the auth middleware under the static file middleware and then updating the http interceptor in Angular, but thought it might be bad practice to have static files be able to load and then redirect after the fact. Any input is appreciated.
In response to your point 1
... My initial thought was setting a cookie defeats the purpose of using a
Authorization header on every request since there is a time the cookie
could then be read even if it's removed on the first api request.
The use of the authorization header is not mearnt to be mutually exclusive to the use of cookies. The idea is to use it when it best suits the problem like in single page applications and native mobile applications. However since it does depend on some kind of client storage, preferably sessionStorage, it is recommended to even sometimes use cookies for the purpose of storing the token if there are issues with the usage of sessionStorage like in old browsers. Hence as long as you use the cookie for storing the token but NOT for authentication, you have not defeated the purpose. Refer to point 1 in the follow up article
https://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies/
If you are wondering "but if I store the token in the cookie I'm back
to square one". Not really, in this case you are using cookies as a
storage mechanism, not as an authentication mechanism (i.e. the cookie
won't be used by the web framework to authenticate a user, hence no
XSRF attack)