Can this be a strategy to defend csrf? (double submit cookie) - javascript

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.

Related

Javascript: How can I force a POST request to treat the user as not authenticated

I'm using Javascript and XmlHttpRequest to POST to another URL on the same site. Users must be authenticated to access the page where the Javascript runs, but I need to submit the POST to the second URL as a non-authenticated user (to prevent the server from running code which is always run for authenticated users). Is there any way to submit the POST so that it appears to come from a non-authenticated user (so the server doesn't pull the user's authentication information from their session and treat them as authenticated for the POST)?
For example, is there a way to open a new session just for the POST, or to change the session ID just for the POST?
Note:
I tried to explicitly perform authorization using credentials for a non-existent user, but that didn't make any difference.
If this can be done using ajax instead of XmlHttpRequest, that's an acceptable solution.
Unfortunately this can not be achieved only in JavaScript, so you will have to make some changes on your server. You have two options:
Either you mark your session cookie as HttpOnly, so it won't be sent together with your request. But this will mean, that all your requests are sent as unauthenticated user.
Second option is use of a subdomain for this endpoint. Cookies are sent with XmlHttpRequests only on the same domain to prevent cross-site scripting. So if you move the server endpoint from www.example.com/myresource to api.example.com/myresource, the cookie will not be sent.

What are some alternatives to CSRF tokens in Laravel?

For non-PHP based web-clients (JSON) making use of Laravel Controllers; What would be the potential alternatives to CSRF tokens in Laravel to secure web requests?
If your API uses an authentication scheme that does not depend on the authentication token being sent automatically by the browser (which practically means the token or session id is not in a cookie), your API is not vulnerable to CSRF. This includes token-based auths, unless the token is stored in a cookie.
If cookies are used to pass auth tokens (including session ids, which is the same in this respect), you need CSRF protection for all requests that change server state (mostly data, but also logon status or privilege level for example).
For Laravel, you need to pass the token value from the XSRF-TOKEN cookie as a request header value in X-CSRF-TOKEN. With jQuery, this is easily accomplished in any client framework by reading the cookie value and adding it to requests:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': csrfCookieValue
}
});
If your client is not browser based, you can implement a different protection than the one in Laravel already. OWASP has a cheat sheet on what your options are, probably double submit is the easiest to implement while being reasonably secure. In very short, you create a random token and send that to the server as a cookie and also as a request header, the server only compares whether the two (cookie and header) match. This works, because an attacker on a differnet origin (domain) cannot set or access a cookie for the application origin due to the same origin policy in browsers.
I think the whole point on using a csrf token is for use inside the app. If you are sending your request via ajax from the app itself then you can simply append the csrf_token to the request. However, if you are sending data from an external source via json then the best way would be to use oAuth to secure access to your api. Luckily laravel has already built this functionality with laravel/passport so implememting it is fairly straightforward.

Don't understand how Django's CSRF protection works

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.

Using digest of your site's authentication cookie for CSRF

I want to protect my WebApi endpoints against CSRF. Angular team recommends to use digest of your site's authentication cookie with a salt for added security. I'm not sure what's the advantage here comparing to random token. What is more, how do you protect login page?
Here is explanation why do you need to protect login page https://security.stackexchange.com/questions/2120/when-the-use-of-a-antiforgerytoken-is-not-required-needed
The method you're describing is detailed here:
Cross Site Request Forgery (XSRF) Protection XSRF is a technique by
which an unauthorized site can gain your user's private data. Angular
provides a mechanism to counter XSRF. When performing XHR requests,
the $http service reads a token from a cookie (by default, XSRF-TOKEN)
and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript
that runs on your domain could read the cookie, your server can be
assured that the XHR came from JavaScript running on your domain. The
header will not be set for cross-domain requests.
To take advantage of this, your server needs to set a token in a
JavaScript readable session cookie called XSRF-TOKEN on the first HTTP
GET request. On subsequent XHR requests the server can verify that the
cookie matches X-XSRF-TOKEN HTTP header, and therefore be sure that
only JavaScript running on your domain could have sent the request.
The token must be unique for each user and must be verifiable by the
server (to prevent the JavaScript from making up its own tokens). We
recommend that the token is a digest of your site's authentication
cookie with a salt for added security.
The name of the headers can be specified using the xsrfHeaderName and
xsrfCookieName properties of either $httpProvider.defaults at
config-time, $http.defaults at run-time, or the per-request config
object.
In order to prevent collisions in environments where multiple Angular
apps share the same domain or subdomain, we recommend that each
application uses unique cookie name.
This appears to be a variation on the Encrypted Token Pattern CSRF prevention method, using hashing rather than encryption, and the salt is acting like the secret key.
It also relies upon a HTTP feature that prevents custom headers from being sent cross domain, much like adding X-Requested-With does.
The part that states "an unauthorized site can gain your user's private data" is slightly misleading, as CSRF does not allow this directly - a CSRF attack allows an unauthorized site to submit your site's forms in the context of the currently logged in user.
An advantage of this method is that you do not need to save anything extra server side. For example, if you are using token-based authentication you can easily verify that the CSRF token received matches the cookie by applying the same hash with the server-side salt. Even if you are using cookie-based authentication you do not need to verify the CSRF token against a separate value stored server-side - you simply hash the cookie value to verify that it matches the passed token.
See this answer for how to protect against login CSRF.

How is using Synchronizer Token Pattern to prevent CSRF safe?

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.

Categories

Resources