Reading this section of the Django docs they recommend setting a csrftoken in a cookie and then having the client-side framework put this in a header which will be validated on a server-side request. However, doesn't having the token in a cookie defeat the purpose because the cookies are sent on every user's request?
Or is the "security" here that Django checks for that value in a header rather than checking the cookie value itself?
I do understand why this works for synchronous submissions, but in that case the csrftoken is written directly to the page rather than stored in a cookie, which seems more secure.
From the OWASP page on reviewing code for CSRF:
Checking if the request has a valid session cookie is not enough, we
need check if a unique identifier is sent with every HTTP request sent
to the application. CSRF requests WON'T have this valid unique
identifier. The reason CSRF requests won't have this unique request
identifier is the unique ID is rendered as a hidden field on the page
and is appended to the HTTP request once a link/button press is
selected. The attacker will have no knowledge of this unique ID, as it
is random and rendered dynamically per link, per page.
You've misunderstood a few things.
The token is always in a cookie; the code you link to is for getting it out of the cookie in your JS so that you can send it back.
And the point is, as your quote shows, that an attacker trying to post from a page that is not on the site will not have that cookie, so won't be able to inject the right value into the form or the header.
I'm not familiar with django csrf protection, but I think it's work like other csrf protections in other frameworks.
The trick is, send csrf token to the client through cookie and client use header to send it back to the server. Server ignore cookie, but not header. How it prevents csrf attack? For example, attacker can bind <img src="yourwebsite.com/action/destroy/data"> (or sends post request through javascript). Your browser sends csrf cookie (and also session cookie) with it. Because header is missing - attack is prevented.
Same with forms. I think both, headers and forms are equal secure.
But in both cases you are lost, if you have a xss vulnerability.
EDIT: as Daniel points out, it's make sense to remove csrf cookie. But this is not for security reason.
Related
used framework: nuxt.js + spring boot(api)
Invoke once api to generate random values and set httpOnly cookie(e.g. key=csrfToken) when the page is first accessed.
The api response is also stored in vuex.
(the response also has token body. with Set-Cookie header.)
When request using axios, If there is the "csrfToken" cookie, add custom header(e.g. key=CSRF_TOKEN_HEADER) to the request.
In the server, if csrfToken cookies are delivered, look up the custom header values to compare them to see if they are the same.
I know that $store is not secure in itself. However, I think CSRF is defensible because $store is not accessible from outside sites.
Please let me know if there is anything wrong with me.
When request using axios, If there is the "csrfToken" cookie, add custom header(e.g. key=CSRF_TOKEN_HEADER) to the request.
Since the cookie is httpOnly, you wouldn't be able to tell if there was or not.
A CSRF attack works by tricking the user into making a request that they didn't intend to make.
The traditional way to do this is to have a form on an attacking website which has the action sent to the website being attacked. When that form is submitted, the request comes from the user's browser and has all the user's cookies for the target website included.
The defence against this is to require that the request includes information that the attacking site cannot know. The CSRF token.
Since the attacking site can't read that token from the user's cookies or the site's session store (depending on where it was stored) or from anywhere else, they can't include it in the form data.
But you aren't using a regular form submission. You are using JavaScript to make the request.
This comes with a built-in defence: The Same Origin Policy and Preflight Requests.
All you need do is force the request to be preflighted (e.g. by setting the Content-Type request header to application/json and including a JSON payload in the body).
This will force a request from the attacking site to make a preflight request. Your server won't have the attacker whitelisted. The browser will therefore never make the attacking request.
If the attacker tries to make a non-preflighted request, it won't have the JSON payload, so your server can reject it as malformed.
I am trying to implement CSRF and SSL(they are not entirely dependent) and listing below my understanding on the topic for having a proof of understanding.
Please feel free to correct me about the understanding.
We see CSRF Token in almost all of our secure applications.
How Cross-Site Request Forgery (CSRF) works :
You logged into your bank account(eg. SBI or JPMC) and are looking at your accounts or it's just sitting their opened on your browser just because you got busy.
Now you receive an email may be text/image or anything on the next tab. The moment the email is received functions like onload etc other java script function may trigger a GET/PUT/POST request from your browser without you knowing about it.
Now things to note is that CSRF can't actually read anything from your secured webpage because the moment you have a proper SSL the secure pages are encrypted. And also CSRF can't steal your credentials. As a matter of fact it can't find out the CSRF token kept inside hidden tag inside secure website because its encrypted. It works only after you have authenticated yourself with the website and it fires requests which tricks the server into thinking that the request in coming from the browser you just logged into and thus server work as per the received request.
Now with hacker trying to open a CSRF attack, it tricks the browser to send url:
<img src="https://www.bankWebsite.com/transfer?amount=1000&destination=8990">
Thus without you knowing, from a session which is authenticated by you, a request is fired telling to transfer amount of 1000 in account number 8990 n BOOM you were robbed for 1000 bucks just like that.
How to protect youself:
CSRF protection can be done in a couple of ways:
1) Verifying the origin of request from header
2) Verifying the target of the request
3) CSRF token
How CSRF token protection works:
The CSRf token in present in the header/cookie. So when the hacker tricks the browser into sending the request to the server, the token is present only in the header and not in form submitted. So when the server goes to check whether the CSRF token received, it tries to match the CSRF token from the header with that received from the form/request. If it's not present/doesn't match then server identifies that it's an attack and stops the request from penetrating further.
Request you all to please correct me if my understanding about the CSRF attack, protection is correct or not ?
Also does it mean without proper implementation of SSL, CSRF is of no use ?
Request you all to please correct me if my understanding about the CSRF attack, protection is correct or not ?
Yes
Also does it mean without proper implementation of SSL, CSRF is of no use ?
If you send the token to and from the client in plain text (instead of encrypting it with SSL) then it can be intercepted by the attacker.
If the attacker knows what token to put in the form data, the protection is gone.
I don't understand fully the point of csrf token protection.
That's the token that says that the POST is coming from my site.
But anyone has access to that token by just verifying their cookie content.
I don't understand then, how is this token protecting me?
To get the csrf cookie, can i make an ajax call to the server and just set the cookie that way? Will that break the csrf protection?
CSRF attacks involve malicious code hosted somewhere. The idea is this:
Attacker lures you to site, and your browser loads malicious code
Malicious code, in the context of that site it came from, attempts to carry out a POST to some known URL at some other secure site: your bank, your hospital, whatever.
If you happen to be logged in to the secure site, then your browser will have a secure session cookie for it. When the malicious code attempts the POST, then, your browser will dutifully send along the cookie. The bad code doesn't know what the cookie value is, but it doesn't have to.
The malicious code does, however, need to know everything else about how to put together the parameters for the POST request to be carried out. That's where the secure CSRF token idea comes from. The malicious code can't actually see what's on the pages in your browser from the real secure site. Thus, a secure site that expects a CSRF token won't see one when the malicious code attempts its POST operation.
(There are probably other variations on this; I'm not a security expert and I don't have exhaustive knowledge of attacks like this.)
csrf token confusion. i can just get it with wget, no cross-origin problems. what's the point then?
The part you're missing is cookies - wget will not send the cookie from the victim's browser along with the request.
The Synchronizer Token Pattern associates the CSRF token (which is visible in a hidden <input> field within the HTML) with the session cookie. If another user makes a request to get the CSRF token from your page, as they are not logged into the same session as their victim, this token will not be useable in their attack.
A CSRF attack works like follows. Imagine the following code on www.evil.com, a site that the attacker has managed to get their victim to visit (e.g. via a facebook post or an email):-
<form method="post" action="https://www.example.com/executeAction">
<input type="hidden" name="action" value="deleteAllUsers">
</form>
<script>document.forms[0].submit()</script>
As the victim is logged into your site (www.example.com) as an admin user, the form submission works and all users are deleted from your system.
The Synchronizer Token Pattern is the recommended way to fix this vulnerability. The CSRF token is a cryptographically secure random string. When a legitimate user loads your form and submits it, your system will check that the token POSTed matches the one expected. Any attacker cannot read the token from your site as any cross site access is protected by the Same Origin Policy
There is another prevention method known as Double Submit Cookies (which may match the method you are talking about). This works in a similar way, although there is no server side state of the CSRF token stored. This requires a cookie value to match a CSRF token that is submitted with the form, but as the attacker cannot set this cookie nor read it, they do not know the value to set the form submitted value to in order to match the cookie.
I need to process an enquiry form of a static website built using Jekyll.
The enquiry form submits a JSONP request (GET) to a PHP app on another domain that processes the request.
Is it possible to prevent CSRF as the form will be static?
I noticed the PHP Slim Framework's CSRF middleware only protects from POST, PUT & DELETE methods, not GET.
If I have a script in the static site build the form on each page load with data requested from the server (cookie value, csrf token as well as field values etc) could that work?
Thanks for your time
No need to protect against CSRF then since the form does not gain anything from being submitted in the context of the current user - if an attacker wanted to submit the form on your website there would be no need to go "cross site"... they would simply submit it.
It sounds like you're after a CAPTCHA to prevent robots submitting the form (if that is what you're really after?).
No.
Defences against CSRF depend on the page from which the request is sent and the server to which it is sent agreeing a unique identifier for the user.
Since the form is static, you can't place that unique identifier in the form.
If I have a script in the static site build the form on each page load with data requested from the server (cookie value, csrf token as well as field values etc) could that work?
Only if it is a server side script (so the form wouldn't be static), otherwise any site could include it to get the token.
I noticed the PHP Slim Framework's CSRF middleware only protects from POST, PUT & DELETE methods, not GET.
This is because GET requests shouldn't be doing anything in the first place, so (unless you are abusing them) there is no need to apply CSRF protection to them.
In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.
I have been reading about using a synchronizer token pattern to prevent CSRF (CSRF meaning Cross-site request forgery.), and I don't understand how it actually safe.
Let's say I have a fake bank site fakebank.com with two urls:
fakebank.com/withdrawForm.html - a GET request which displays the withdraw money form
fakebank.com/doWithdraw - POST to this url to do the withdraw
My understanding of the security flaw is that maliciousSite.com can spoof a POST request to fakebank.com/doWithdraw, and if you're currently logged in to fakebank, the POST will be successful.
Let's say we implement a Synchronizer Token Pattern which will embed a secret code on fakebank.com/withdrawForm.html. Can't maliciousSite.com just spoof a GET request for that form, parse the html result, get the token, and then create the POST request with that token?
This is assuming fakebank.com isn't checking HTTP Referrer or Origin or maliciousSite.com is successfully spoofing that the Referrer/Origin is fakebank.com.
The reason why this is secure, and maliciousSite.com cannot simply do a GET, steal the token, and then do a POST is that the request is done by the user's browser, not by the server at maliciousSite.com. All data returned from fakebank.com is returned to the user's browser, not to the server at maliciousSite.com. If maliciousSite.com does perform a GET to retrieve a token, it will be a different token than was issued to the user. maliciousSite.com cannot set this cookie into the user's browser to be submitted to fakebank.com because of same-domain restrictions.
The CSRF POST attack works by tricking the user's browser into requesting fakebank.com/withdrawForm.html directly using a properly formed POST request. The server at fakebank.com happily executes the requested POST, thus transferring funds using the parameters supplied in the POST body (which include a destination account belonging to the attacker that was put there by maliciousSite.com). The server at maliciousSite.com doesn't need to see the data returned, because the action has been taken (unless fakebank.com uses these CSRF tokens, which the maliciousSite.com can't possibly know unless it has been divulged in some way. It can't ask for it). If fakebank.com is using CSRF tokens, then maliciousSite.com will submit a POST request that is missing the token, thus indicating a potential CSRF attack in progress.
Vulnerabilities of this method include using a CSRF token that is not kept sufficiently secret and is divulged in some way. Also, if the CSRF token is not sufficiently random, then maliciousSite.com might be able to guess it. Also, if there is a weakness in the browser's enforcement of same domain policy, this could be exploited. Generally speaking, modern browsers are not vulnerable to this.
Please let me know if this is an insufficient explanation and I'll attempt to articulate it a little better for you.
And that is exactly the point. The Same Origin Policy in the browser does not allow GET requests to other sites. So no site can GET the CSRF token from another just using Javascipt within the browser.