CSRF, CORS and my approach to authentication - authentication

I've seen many questions about CSRF attacks and GET requests, and I'm trying to work out what I need for my app's authentication system.
My stack is an SPA React app hosted at app.site.com, and an API at api.site.com.
My plan is to do the following.
On load, the React app will call a GET route on the server to get the current user.
This route will check the cookies, look for an httpOnly cookie with a valid token, and if so, send back a loggedin token which will be stored in application memory.
Each subsequent request will then be checked for both tokens in order to succeed.
A potential flaw in this that I can see is as follows:
Could an attacker send a victim to www.other-domain.com, which will trigger a script that calls my /user endpoint? That would send the httpOnly cookie, so the bad site/script will now get back my application memory token, and could then theoretically send other requests. I know I can protect against CORS with this, but is that enough?
I've read that CSRF is a 'write-only' attack, but in this instance I can see that it could be a problem on a GET request.
My questions, then, are:
Is the setup above workable from a security standpoint?
Would using a samesite cookie for the httponly cookie negate the need for the application memory token?
Are there any points in this process that I'm missing?
I've done a lot of research, but would love to hear the thoughts of more experienced engineers. Thank you in advance for any help you can provide.

I've read that CSRF is a 'write-only' attack
In general you're right. CSRF can be used to execute a create or delete action (or any other side effect) on the server - which depending on your server implementation can also happen with a GET request. In some rare cases CSRF can also be used for DoS (Denial-of-Service), for example when you have a very expensive server-side computation in your API, that can be triggered too easy and often via CSRF.
Are there any points in this process that I'm missing?
You would need CORS for your scenario to work (SPA on app.site.com and API on api.site.com). I'd try to avoid using CORS if possible, because 1. it can introduce security problems if configured poorly, 2. it can have a negative impact on performance when the browser runs preflight requests, which effectively will double the roundtrip time, and 3. you introduce tight coupling between your SPA and your API.
And that's where BFF (backend for frontend) comes in handy: You simply use app.site.com/api for your API calls from your SPA, and your app.site.com server will act as a proxy and forward these requests to api.site.com.
Now you don't need CORS at all, and you decoupled your SPA and API, because now you can intercept your API calls at the BFF level and transform the requests made to the API and also transform the responses, aggregate data, combine multiple API requests, etc.

Related

How to prevent sending requests to RESTful API directly on a SPA project?

I have a Single Page App application which is working based on RESTful APIs. Generally, all APIs have a route access which can be found while inspecting web application.
Although I have authentication mechanism based on user tokens, a hacker can find the API routes and use his given token to send many requests to APIs directly.
What is the best solution to prevent such behavior? I was thinking about CSRF, but as APIs are based on REST, and the project is a SPA, I think I should have another mechanism.
May you help me please?
You cannot authenticate the client application, it is not possible. If a user can send a request from an spa, because they have the credentials and the endpoints to send them to, they can use whatever client from Burp through ZAP or Postman to curl or whatever else to send the request.
Your API must be resilient, you should have rate limiting, user quotas, monitoring and secure operation practices in general on the server side based on your threat model to mitigate this risk.
In practice this might mean hosting the API in a way that's resilient to DoS on the network level, having a per-user request rate limit, identifying functionality that is a burden for the server for some reason (calls external services, sends email and so on) and protect/monitor those even more carefully. There is no one size fits all solution.

API Authentication for PWA

The Setup
We’re building a PWA (progressive web app). The main components are the app shell (SPA) and the API. The REST API will supply the data needed for the app, while the SPA will handle the rest (as per Google recommendation).
The Problem
Authentication of the end-user seems problematic because the web browser needs to be accounted for. We want the user login to persist through closing down the browser.
We’ve done the research about the possible ways of going about it, however we’d like to ensure that we’re not going in the wrong direction.
Solutions we’ve considered
Session based authentication - the user sends username and password to /accounts/auth and receives a HTTP only cookie with the session ID. The session needs to be stored in a database or Redis. The issue with this option is that cookies are automatically sent by the browser therefore we need a CSRF protection in place. Using the Synchronizer Token Pattern a new token would be generated every time a state changing request has been made e.g. POST. This means that the application needs to supply a CSRF token with every request so that the PWA can send it via AJAX. We determined that it’s not ideal as the user can send multiple post requests in a quick succession making some of them fail and resulting in a bad user experience.
We could also use this method without the CSRF by limiting the CORS policy to same domain and adding a header requirement which technically should stop all CSRF, however we're unsure how secure it would be.
JWT token based authentication - the user sends username and password to /accounts/auth and a new JWT token is issued. The JWT then needs to be stored in localstorage or a cookie. Using localstorage means that JWT is XSS vulnerable and if the token is stolen, an attacker can impersonate the user completely. Using cookies we will still have a CSRF issue to resolve. We considered a double submit cookie method but the CSRF would only refresh every time the JWT is reissued which creates a window for the attacker to find out what the CSRF is. It is not clear which method is best to use.
Session based authentication + JWT token authentication - the user sends username and password to /accounts/auth, a session is created, a HTTP only cookie is set in the browser and a JWT token is sent back to the user. The PWA can authenticate requests with the JWT and whenever the JWT expires the app calls /accounts/auth again to acquire a new one. The /accounts/auth endpoint would still need to be CSRF protected, however the impact of it on usability would be minimised.
There seems to be a large amount of articles claiming that localStorage is insecure and shouldn't be used so why are high profile organisations like Amazon still recommending it? https://github.com/aws/amazon-cognito-auth-js - this SDK uses localStorage to store the token.
You don't need to generate new CSRF token each time a client make a request. It's much easier to use a scheme like token = hash(id + secret + current_day). You only need to update it once a day, or even employ mixed scheme (if the token is invalid today, but is okay for the previous day, the server accepts the operation and returns new token in a predefined header for client to renew it). You may also use the cookie as an id, making the token totally stateless and much easier to check, no need to store them in the database.
Here is how I look at it.
JWT token authentication : with this approach, you can always use a time-bound token with its expiration set to say 2 hours or something?
Or another approach would also be to try and see how you could use some of the approaches the Credentials Management API suggests for example, auto-sign-in of users whenever they come back.
Stuff like 2-step verification with OTPs for instance; for very important features in your web app can be a choice. In this case basic stuff are tied to whichever one time authentication method you have.
Actually, you can also use user-defined pins or short codes (seen a lot in banking apps) to grant access to some features in your web app.
Hope this helps, or sparks some ideation.

Seperate Front and Back-End - Persistent Authentication with Vue/Webpack/Hapi

I apologize in advance for the wall of text.
I'm working on a project for school. We are trying to create a messenger application with a separate front/back-end.
For the back-end we decided to use Hapi (NodeJS), which is now a working API that authenticates based on JWT.
Let's assume the back-end is running on http://localhost:3000.
To interact with the API and create an actual user-friendly messenger, we decided to go with VueJS, using Vuetify as a design framework.
We created a webpack template with vue create (Vue CLI3) and started designing a register/login page, which is served on http://localhost:8080.
I have now arrived at the point where I have to think about a way to show different content based on authentication. I can request a JWT from the API by logging in, but I don't want to store it in local storage, as that is insecure. The same goes for cookies, if they are not HttpOnly.
I feel like a messenger app wouldn't require a user to login every time they restart their browser, so I need some kind of persistence, which leaves only one option (please correct me if I'm wrong): HttpOnly cookies containing our session data, a JWT in this case.
Seeing as I can't set HttpOnly cookies with Vue (as it's JS), how would I go about creating persistent authentication?
We want a user to be redirected to a login page if they aren't logged in. If they are, they can access and see extra functions (Vue components). If they refresh, or restart their browser, they should still be logged in and able to access the functions the API offers (like sending messages to others, reading their own messages). This, while not being vulnerable to XSS.
I have unleashed my Google-fu for 2 days straight now and can't find a good answer. People use VueX which isn't actually persistent and only works persistently with local storage, which again, is insecure for storing a JWT.
Is this at all possible with a separate front/back-end? If I send back a cookie with Hapi, that might work and get stored in the browser, but that'll be HttpOnly so how do I read it with the front-end to determine if I am authenticated?
Please be as verbose as possible, as I seem to miss a lot of design principles and context that are apparently very obvious to everyone else on the internet. I honestly believe that if there is a very good answer to this, that it'll help other people starting out tremendously.
TL;DR: How to create persistent authentication with a Vue front-end and Hapi back-end, without sacrificing security?
as I know, HTTPOnly cookies can be set only on https protocol
source : https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Secure_and_HttpOnly_cookies
and I think it is safe to store jwt token in localstorage as long as you use https
another related thread about jwt storing in reactjs : https://stackoverflow.com/a/44209185/10661914

Session cookies vs JWT

Question: Does using cookies for user session handling hinder the scalability of your backend because all the API's have to live on the same domain. Basically if one API starts to get a lot of request and you want to add another server to off balance the load you would have to add an entire webserver rather than just a small micro webserver with the API running on it mainly because cookies are used to authenticate user request and cookies don't survive CORS request. Am I right or don't know what the hell i'm talking about lol need some opinions I suggested we make all API's micro services and use JWT for user sessions
Cookies have almost nothing to do with scalability, as you may use subdomains. You can continue using them, as long as you have a common session store for all your services.
JWT is mainly good for server-to-server authentication, I using it as your main authentication flow is a big overkill, in my opinion.

How token based authentication helps in cors, cdn, CSRF , mobile ready?

I was reading articles about token based authentication.
And when I was going through this article "Cookies Vs Tokens", I did not understand the following four points (I have asked my doubts below each of the quoted points)
Cross-domain / CORS: cookies + CORS don't play well across different
domains. A token-based approach allows you to make AJAX calls to any
server, on any domain because you use an HTTP header to transmit the
user information.
Why now there will not be cors problem ? What if someone one from the neighboring tab in the browser steals your token(because in javascript of that domain there is code which can clearly tell where the token is stored and how it is retrieved) and starts making
requests ?
And more over it is said "cookies + cors" . why is it said that cookie and cors don't play well ?
CDN: you can serve all the assets of your app from a CDN (e.g.
javascript, HTML, images, etc.), and your server side is just the API.
Why is this an advantage in token based auth systems ? We were using cdn's even when we were doing cookie based authentication right ?
This was because script tags can call scripts from other domains any way right ?
CSRF: since you are not relying on cookies, you don't need to protect
against cross site requests (e.g. it would not be possible to
your site, generate a POST request and re-use the existing
authentication cookie because there will be none).
What if someone one from the neighboring tab in the browser(from some other domain) steals your token and starts making
requests ? I cannot understand this either.
Mobile ready: when you start working on a native platform (iOS,
Android, Windows 8, etc.) cookies are not ideal when consuming a
secure API (you have to deal with cookie containers). Adopting a
token-based approach simplifies this a lot.
Did not understand it completely . Can someone explain , how?
The linked article is a bit sloppily written and does not properly define and distinguish between the various concepts.
First, you have to define what exactly you mean by "token based". The article does not do that, but it seems it has OAuth 2.0 JWT access tokens with the Bearer Token Usage (http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html) in mind. This means that:
Bearer access tokens are used. The upside of bearer tokens (as opposed to MAC token usage) is simplicity of usage -- all a client needs to pass to a server is a token. The downside is that whoever gets hold of such a token is considered its rightful owner, so he can do whatever he wants with it.
Tokens are passed in the Authorization HTTP header, following a specific syntax.
Then you have to define what you really mean by "cookie based" authentication -- which again, the article does not do. A cookie, essentially, is just a transport mechanism to pass data back and forth between client and servers of a specific domain, without the client having to do anything explicitly. So you can really stuff pretty much anything into a cookie -- even OAuth 2 access tokens.
What the author seems to have in mind is server side-managed sessions where a session id is passed in a cookie.
With these definitions in mind, it is possible to answer your questions:
Cross-domain / CORS: cookies + CORS don't play well across different domains. A token-based approach allows you to make AJAX calls to any server, on any domain because you use an HTTP header to transmit the user information.
This is true, but for different reasons: Cookies are scoped to a specific domain, so as long as you use cookies to pass a session id between clients and servers, you are bound to having to put all servers under one domain. This looks like a limitation, but the true limitation is somewhere else -- when using server side-managed sessions, a session id will only make sense to those servers who have access to the server side session management. Any server outside the domain most likely cannot make any sense of a session id.
A JWT access token, however, is self contained and can be interpreted by other parties as well. This is why access tokens are well suited for cross-domain/cross-service calls.
CDN: you can serve all the assets of your app from a CDN (e.g. javascript, HTML, images, etc.), and your server side is just the API.
Yes. But this does not really matter in practice because anyting you put into a CDN will most likely not require authentication in the first place -- so this is kind of a silly argument.
CSRF: since you are not relying on cookies, you don't need to protect against cross site requests (e.g. it would not be possible to your site, generate a POST request and re-use the existing authentication cookie because there will be none).
The danger of cookies w.r.t. CSRF is that they are passed implicitly to the server -- the browser adds a cookie to the request, regardless of whether it was good of rogue code that triggered the request.
When tokens are passed in a cookie, this danger applies to tokens we well. However, when they are passed in a header (as the Bearer Token Usage spec defines), this danger does not exist as the header needs to be added to teh request explicitly, every single time. This makes this approach more CSRF-safe than cookies.
However, when the rogue code can get hold of the token some other way (because it was passed as a URL parameter, for example (which the spec allows), it is still possible to make CSRF attacks with tokens.
Mobile ready: when you start working on a native platform (iOS, Android, Windows 8, etc.) cookies are not ideal when consuming a secure API (you have to deal with cookie containers). Adopting a token-based approach simplifies this a lot.
Dealing with cookie containers is usually easier than setting up OAuth, so I do not buy into this one.
Alright, I'll try to go through these in as structured a way as possible:
CORS + Cookies: Cookies were never meant to travel across domains. A cookie must be submitted to the server from its origin, cross-origin cookies don't exist. There is no need to worry about another application accessing the token if it's stored in localstorage since that one is site-specific, e.g every site gets it own allotted space of localstorage.
I'm not certain about this one. I'd assume they mean an authenticated CDN, e.g you provide a token to get access to the resources
Again, the token won't be stolen by a neighbour, because of how localstorage works. If you're worried you could actually issue a new token from the server with every response, effectively making one-time use tokens. That way, even if your token is compromised, it is far less likely to work.
Cookies are fairly complex structures, and if you one day decide you want to consume your API on a mobile device, it will be much easier to use a token, which is just a string (compared to a structured object)
The most important difference is that tokens are stateless, while cookies are not. Cookies will contain information about the authenticated user and context-specific data. A token, on the other hand, is just a string that an API consumer assumes can be used to access restricted data.