can anybody explain what exactly the cookieToken parameter is when I call the function in MVC: AntiForgery.Validate(cookieToken, formToken);
Is it possible to use the cookieToken as a Session identifier to identify the user and current session?
No.
ASP.Net generates a random Cross-site Request Forgery (CSRF) Token on every request (even for the same user). You can verify this by going to your website and looking at the source. There will be a hidden field "__RequestVerificationToken" that will contain a string of random letters and numbers. When you refresh the page it will randomly generate a new set of letters and numbers.
This is not to identify a user to a particular session, but to identify a user to a single request.
To read more on CSRF attacks to understand the purpose of this token, read OWASP's Top 10 on Cross-Site Request Forgery
Related
I'm implementing a REST API that also provides functionality for authenticating users. Authentication requires an user to send a POST request with the following data in the body:
{
"userOrEmail": "spook",
"passowrd": "Test1234"
}
If the username and password match, the user gets back a token from the server, while if they don't, the server returns 401 Unauthorized, with the following header:
WWW-Authenticate: Credentials realm="http://localhost:9000/auth/users/credentials"
Is that header acceptable? realm contains the location where the user can try to authenticate again.
It appears to be acceptable, but maybe not optimal except under very specific conditions. From RFC1945:
The realm value (case-sensitive), in combination with the canonical root URL of the server being accessed, defines the protection space. These realms allow the protected resources on a server to be partitioned into a set of protection spaces, each with its own authentication scheme and/or authorization database. The realm value is a string, generally assigned by the origin server, which may have additional semantics specific to the authentication scheme.
So, you can, but I might be paranoid about multiple applications using the same authentication and inadvertently cross-authenticating if they were to share the same realm name. Better would be to isolate the realm by application, just to be on the safe side.
No, it's not acceptable.
a) There is no authentication scheme called "credentials".
b) The purpose of the "realm" parameter is different.
From my research, the proper way to protect against this is to set a NONCE with every GET request that returns a form and then check for the NONCE on the POST request. However, someone could still write a script to GET my form along with the NONCE and then POST it back with the NONCE.
Since this is such a widely known vulnerability, shouldn't browsers already take care of that by not allowing cross-domain ajax calls? If not, does ASP.NET MVC 4 already have a built-in mechanism to protect against this?
Those nonces are used for protecting against cross site request forgeries. A cross domain ajax call is not necessary to make that happen - and browsers do have protections against those. CSRF is a vulnerability because when a browser makes a call to your site, it sends the session information for your site, regardless of the page that told the browser to make the call. The browser can be told to make a get request to your site.com by including an img tag on evilsite.com that points to a page on your site.com. If when that get request is processed by yoursite.com you validate the nonce, there is no way that a drive by of evilsite.com would know the nonce. Similar things can be done for post requests as well.
This page seems to have some information about how to mitigate this in ASP.NEt MVC: http://www.asp.net/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages
Cheers,
Stefan
Yes there is a built in mechanism. HtmlHelper.AntiForgeryToken, which can be used to help protect your application against cross-site request forgery. To use this feature, call the AntiForgeryToken method from a form and add the ValidateAntiForgeryTokenAttribute attribute to the action method that you want to protect.
CSHTML file:
#Html.AntiForgeryToken()
Controller:
[ValidateAntiForgeryToken]
public ActionResult Edit(User updatedUser)
You'll note that the token involves two safety measures -- a form field and a cookie:
To generate the anti-XSRF tokens, call the #Html.AntiForgeryToken()
method from an MVC view or #AntiForgery.GetHtml() from a Razor page.
The runtime will then perform the following steps:
If the current HTTP request already contains an anti-XSRF session
token (the anti-XSRF cookie __RequestVerificationToken), the security
token is extracted from it. If the HTTP request does not contain an
anti-XSRF session token or if extraction of the security token fails,
a new random anti-XSRF token will be generated.
An anti-XSRF field
token is generated using the security token from step (1) above and
the identity of the current logged-in user.
If a new anti-XSRF
token was generated in step (1), a new session token will be created
to contain it and will be added to the outbound HTTP cookies
collection. The field token from step (2) will be wrapped in an element, and this HTML markup will be the return
value of Html.AntiForgeryToken() or AntiForgery.GetHtml().
Reading:
XSRF/CSRF Prevention
Wikipedia CSRF
You should also take a look at the concept of stateless CSRF protection. There are 2 standard approaches to achieving this: the Encrypted Token Pattern and the Double Submit Cookie pattern. The Encrypted Token Pattern leverages a Rijndael-encrypted Token which contains a built-in nonce value that can’t be read by scripts, and is a very strong cryptographic structure.
I work on ASP.NET and was just reading this from the amazon directory http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAuthentication.html where it states
Informally, we call this process "signing the request," and we call
the output of the HMAC algorithm the "signature" because it simulates
the security properties of a real signature. Finally, you add this
signature as a parameter of the request, using the syntax described in
this section.
When the system receives an authenticated request, it fetches the AWS
Secret Access Key that you claim to have, and uses it in the same way
to compute a "signature" for the message it received. It then compares
the signature it calculated against the signature presented by the
requester.
But i presume both the requests wont be same right. Request is signed (great!!) but HMAC of the response from the client browser is going to be different since it contains extra data Right? so how come requests can validate even though they are valid
You need to read the whole of the paragraphs you quoted from. Right before the piece you quoted it says:
To authenticate a request, you first concatenate selected elements of the request to form a string. You then use your AWS Secret Access Key to calculate the HMAC of that string.
So you calculate your HMAC from those selected elements, and when you submit the request, the server calculates an HMAC from those same elements, and then they are compared.
Implementing CSRF tokens in hidden form fields is the standard protection for CSRF for form post requests.
However, how would you implement this for GET requests? Or ajax requests that POST json data instead of x-www-form-urlencoded for the request body? Are these types of things all handled on a case by case ad hoc basis?
OWASP says this about CSRF and GET requests:
The ideal solution is to only include the CSRF token in POST requests
and modify server-side actions that have state changing affect to only
respond to POST requests. This is in fact what the RFC 2616 requires
for GET requests. If sensitive server-side actions are guaranteed to
only ever respond to POST requests, then there is no need to include
the token in GET requests.
Also, OWASP notes:
Many implementations of this control include the challenge token in
GET (URL) requests [...] while this control does help mitigate the risk
of CSRF attacks, the unique per-session token is being exposed for GET
requests. CSRF tokens in GET requests are potentially leaked at
several locations: browser history, HTTP log files, network appliances
that make a point to log the first line of an HTTP request, and
Referrer headers if the protected site links to an external site.
The trouble here is that if a user's token is leaked, you're still vulnerable - and it's all too easy to leak the token. I'm not sure that there's a good answer to your question that doesn't involve converting all of those GET requests to POST requests.
It's worth noting that the Viewstate feature in ASP.NET WebForms does offer some protection against CSRF, though it's very limited - in fact, it also only protects POSTback requests.
To state this more simply, you shouldn't use a GET request as an entry point to any function that does something beyond return a read only resource for a browser to render. So don't have an AJAX script make a GET based call to a URL like transferMoney.aspx?fromAcct=xyz&toAcct=abc&amount=20.
The HTTP specification states explicitly that HTTP GET requests should not have side effects. It's considered best practice to keep your GET requests idempotent whenever possible.
I've written an article about protecting ASP.NET MVC against CSRF, it spells out a practical approach to applying the AntiForgeryToken to POST controller methods on your site.
It depends on the CSRF-protection pattern you're applying. First off, CSRF applies to endpoints that change state. If you're GET requests change state, then I advise that you modify them to POSTs. Having said that, it is a valid point.
The ideal place to persist Tokens is in the AUTH Header. This is the lowest common denominator across FORM-POSTs, AJAX and GET requests. You could of course store the Token in a Cookie, but there is a vulnerability in this design when applied to a multi-domain site.
You can parse the Token from a hidden field during FORM-POST without issue. Not much point in changing that. Assuming that your GET requests are invoked with AJAX, you can leverage JQuery's ajaxSetup method to automatically insert the Token on every AJAX request:
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", "TOKEN " + myToken);
}
});
There is a relatively new pattern gaining traction called the Encrypted Token Pattern. It's described in detail here, and also on the official OWASP CSRF Cheat Sheet. There is also a working implementation called ARMOR, which may offer you the flexbility you're looking for across various types of requests.
I read this post Understanding CSRF - Simple Question
But I still do not understanding how the CSRF token can prevent a CSRF token.
The main problem which confused me is that why the attacker can make any http request to my site, but he cannot read back the response?
1、If I post a http request to get token before every post request, attacker also can make an "get token" request to get token.
2、If I set token to the hidden input while the .html page is loading, attacker also can make a "get html" request to get the this .html page and read the value of hidden page.
I just don't understand why the attacker can make request but can not read the response?
The attacker cannot make the request himself at all. What he can do is trick his victim (or the victim's browser) to make that request. So any response would go back to the victim's browser, too.
The problem here is that the attacker can choose the URL, and even without seeing any response, accessing that URL may have harmful consequences for the victim.
The reason why the attacker needs to trick the victim into making the request (as opposed to just accessing the URL himself) is that if the victim does it, the victim's session cookies will also be sent along, so it looks like an authenticated action for the server.
If I set token to the hidden input while the .html page is loading, attacker also can make a "get html" request to get the this .html page and read the value of hidden page.
The attacker can only get a hidden input for his own session, not for the victim's session. This hidden input will be different from session to session (otherwise there is not point).
The CSRF token makes sure that every (critical) request includes a random piece of data that must match the user's session. This way, an attacker cannot just guess what the complete URL would be, and trick someone into clicking on it.