Is CSRF middleware needed if HTTPOnly cookie is used? And should it be session-based? - security

Now authorization sheme looks like this:
If the user input the correct data, the server generates a unique sessionKey, inserts it into the session table with FK for this user. In response to a JSON request, I send this sessionKey. The web client sets this key it in a cookie.
But the problem is that if the web client stores this cookie, JS will have access to them, and it is not safe.
The alternative is to set the HTTP-Only cookie. But it is not clear whether it is necessary to use CSRF middleware in this case. Does the HTTPOnly attribute solve the problem of XSS / CSRF attacks? If it does not decide and you need a CSRF middleware, then the csrf cookie must be a session cookie.
The problem is that all the csrf middlewares for my framework do not allow to use of the session csrf cookie. Alternatively, write my own middleware.
Do I understand correctly that the csrf middleware stores the token that I gave to the client in RAM and verifies on every request? But then what's the point of this token if it can be intercepted in the same way as an authorization cookie?

Let's start with stating that Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF) are two different animals.
XSS is about embedding malicious code into a site to have it executed on the client machine. No HTTPOnly flag can mitigate this.
CSRF is about embedding malicious code on some third party site and sending you the link to the third party site. The malicious code can try to fire GET/POST request (which can bypass browsers Same Origin Policy) and execute some unwanted actions on the site the user is logged to. It's easier to understand this with an example:
You are logged into your site on https://example.com. You are authenticated with a cookie.
Someone sends you a link to https://malicious.net. You open the link in a separate browser tab.
Malicious code is being executed and fires a request to https://example.com/deleteAccount=1. Cookie will be attached, request will be authenticated and executed.
The answer is no - the HTTPOnly flag will not mitigate any of this. But let us concentrate on solving CSRF issue. What options do you have?
In fact you have many: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
IMO the easiest could be passing the sessionKey not over a cookie, but over an Authorization header. This can not be done automatically by the browser so you would be safe from CSRF attacks.

Related

CSRF prevention using local storage and cookie

The following talk https://youtu.be/67mezK3NzpU?t=2408 at 40:08min, Hubert mentions that the best way to prevent a CSRF attack is to do the following:
Generate a random id server side - lets call this the CSRF id.
Add this id to your jwt cookie. Also add a response header with the id (e.g. csrfId: xxx)
Have the client save the id to local storage.
On each request, the client should append a header with this id.
On each request, the server should verify that the id in the received cookie matches the one in the received header.
My question is: what would stop the CSRF attacker reading the cookie manually, getting the ID and then adding that to the attack request?
Also, wont localstorage leave the ID vulnerable to a XSS + CSRF combination attack? (I'm not sure this is possible)?
what would stop the CSRF attacker reading the cookie manually, getting the ID and then adding that to the attack request?
Setting the cookie attribute HttpOnly makes it inaccessible to Javascript. Using a custom request header prevents an attacker from adding the ID to the attack request:
«This defense relies on the same-origin policy (SOP) restriction that only JavaScript can be used to add a custom header, and only within its origin. By default, browsers do not allow JavaScript to make cross origin requests with custom headers.» -https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#use-of-custom-request-headers
Also, wont localstorage leave the ID vulnerable to a XSS + CSRF combination attack? (I'm not sure this is possible)?
CSRF protection can be bypassed if you have a XSS vulnerability, regardless of using localstorage.
However, OWASP explicitly recommends not storing the CSRF token in cookies or local storage.
So I think your question is warranted, and I don't understand how that can be the best way to prevent a CSRF attack.
If I may, I recommend you check out the OWASP CSRF prevention cheatsheet if you haven't seen it already.

Confusing about CSRF protection strategies

I am testing a web application. CSRF is applied and sent in cookies and header but not in the form as hidden input. The csrf token does not change for every request but it change during the session. How often should the csrf token change ? Should it change per session or per request ? should the client or the server set the csrf token ? what is the best strategy to apply csrf protection? double submit cookie ? Triple Submit Cookie ? or any other new strategy ?
I'm just going to attempt to answer your questions one by one here.
How often should the CSRF token change?
You can change your CSRF token once per session. Changing it once per request offers no real security advantage and if anything, only serves as an easy way to waste resources and limit usability. For example, a user will not be able to hit the "back" button because they will have an outdated CSRF token, or if they try to resubmit a form with new values (such as after a validation error) it may not send.
Should it change per session or per request?
As discussed, it should change per session. The only time that a user should be given a new token per request is at login. This is to prevent a session fixation attack leading to a CSRF attack possibility.
For example: An attacker accesses the site and generates a new session. They take the session ID and inject it into a victim's browser (eg via writing cookie from a vulnerable neighbour domain, or using another vulnerability like jsessionid URLs), and also inject the CSRF token into a form in the victim's browser. They wait for the victim to log in with that form, and then use another form post to get the victim to perform an action with the still-live CSRF token.
To prevent this, invalidate the CSRF token and issue a new one in the places (like login) that you're already doing the same to the session ID to prevent session fixation attacks.
Should the client or the server set the CSRF token?
The server - always on the server! You want to generate the token from a trusted source, as per OWASP guidelines. This ensures that you know exactly where the token is generated and limits attack surface since an attacker cannot control what happens on the server.
What is the best strategy to apply CSRF protection?
I think CSRF is a very in-depth topic and can't really be summed up in just a few words. This is where a little research and reading can go a long way. I would recommend you take a look at the OWASP CSRF Prevention Cheat Sheet.

Why is a csrf token needed when a session cookie is used?

Say I login through an opendID connect provider and am redirected to my callback www.mysite.com/auth/callback. I then create an httponly cookie, which contains an id referencing to my received tokens, that is passed to the browser at wwww.mysite.com/. How would another site submit a request that contains that same session cookie? Does the browser not pass only the cookies of the requesting domain. So if www.evil.com tries to make a request to www.mysite.com/api/endpoint, won't the session cookie not be passed, making the forged request invalid?
Am I missing something basic here??
When web browsers send a request to a different domain, they're nice enough to first check if they already have cookies for that domain, and if they do, then they send them along with the request. So, if you're on a web application trying to send a request to your app, it'll send that request along with your cookies. The idea behind the anti-forgery token is that even when the web browser sends all that information, if the token doesn't match with the one that you create on a legit request submitted from your application, it'll fail.
If you don't want your cookies being sent via cross-site requests, you can use the samesite flag for your cookies. Here you can decide between Strict and Lax mode. In Strict mode, you'll never send your site cookies via cross-site requests, so you don't need to care about session cookies being sent. The problem here is that if you're redirected from a different site, from example, if you're here, and try to go to facebook (if facebook used strict mode), your cookies will not be sent, and you'll need to authenticate again (it can be an annoying or a good feature, depending of your application and your user-base).
The Lax mode is pretty similar, but in this mode, you'll only send your cookies via safe HTTP verbs (GET, HEAD, OPTIONS and TRACE), so you still get your protection against POST/PUT XSRF attacks, and you don't have an annoying behaviour for the GET requests. It's up to you to decide which one will be the better option for your app.
More info about XSRF and samesite cookies: http://arnoldcer.com/2017/03/14/cross-site-request-forgery-what-it-is-how-to-exploit-it-and-how-to-defend-against-it/

Using JWT instead of Cookie on SSL enabled site

Instead of using a cookie I'm using a JWT token which gets send with every request. Every request is a POST request so that the token does not get saved in the browser's history.
It's a single-page app.
The token looks like:
{
userId: 12345678,
expires: <UNIX timestamp>,
otherInfo: <something>
}
Everything is SSL secured.
The token is created on the server when the user logs on.
Would this be a good way to replace a cookie or do you see any flaws?
No, this is not a good solution. Using cookies (with a httpOnly flag) for cross-request persistence is not optional - it's the only way to safely store session credentials, in such a way that on-page JavaScript code cannot access it directly.
This is essential to prevent eg. session stealing in an XSS attack, by ensuring that scripts cannot access the credentials, but they can still be used in requests to the server.
Your use of JWT doesn't seem to really solve a problem, either - why can't you just use session cookies using an existing session implementation? This kind of thing is precisely is what they're made for.

Why does ServiceStack authentication use cookies rather than a sessionId header?

I'm loving using ServiceStack, but one question has come up from a colleague that I cannot answer. The Authentication mechanism sets a ss-pid and an ss-id cookie, which is explained here: https://github.com/ServiceStack/ServiceStack/wiki/Sessions
When trying to access a restricted resource, these cookies need to be provided, otherwise you'll receive a 401 Not Authorized result.
My question is this. Why use a cookie rather than a custom HTTP header value that includes the sessionId or equivalent cookie values? Is it because the cookie inherently has its own mechanism to maintain expiration? What were the design decisions undelying the use of cookies over HTTP headers?
HTTP Cookies are inherently sticky and is the most appropriate way for maintaining sessions over HTTP. After the server instructs the client to add a Cookie, every subsequent request that the client makes back to the same server will also retain that cookie - this what enables the Client/Server session.

Resources