I'd like to close the CSRF vulnerability for posting raw JSON via AJAX.
I'm familiar with MVC's mechanism for automating CSRF prevention using the ValidateAntiForgeryTokenAttribute
and @Html.AntiForgeryToken()
; however, if I understand correctly, this mechanism requires that the POST
be done with a Content-Type
of application/x-www-form-urlencoded
(or similar). Is there a built-in mechanism in ASP.Net MVC that will reject CSRFs for POST
requests with Content-Type
of application/json
? If not, am I stuck with putting the anti-forgery into the JSON object itself? Can you recommend a technique for protecting JSON POST requests from CSRF vulnerability with the same level of security as the form-based approach built into ASP.Net MVC?
Applications can be developed to only accept POST requests for the execution of business logic. The misconception is that since the attacker cannot construct a malicious link, a CSRF attack cannot be executed.
Introduction — CSRF: In this write up I will explain how to identify the JSON CSRF vulnerability and the challenge I face to escalate this bug in a recent project. Generally, the JSON CSRF is not always possible in every web application that uses the JSON body. Mainly it depends on the authentication mechanism.
This question brings up an interesting discussion.
Provided that the request Content-Type is application/json
, then CSRF is not a concern. This is because application/json requests must be submitted via XmlHttpRequest
, and the cookie which is a necessary part of the verification of your AntiForgeryToken cannot be passed cross-site, but must adhere to the Same Origin Policy.
However, it is possible for a malicious user to submit a request via application/x-www-form-urlencoded
which contains the information which will appear to be a valid JSON request, and which will pass any authorization cookies back to your application. There is a more detailed discussion of this at http://forums.asp.net/t/1624454.aspx/1?MVC3+JSON+Model+binding+not+working+with+AntiForgery and at http://aspnet.codeplex.com/workitem/7472, where I post a proof-of-concept.
While it is possible to include the __RequestVerificationToken in a JSON request, a better line of defense is to create an Attribute to verify that a request is of type application/json
, since any other request being submitted to your action which expects JSON is in fact invalid, and should not be handled.
I expect that this security issue will be addressed in MVC 4.
UPDATE:
Here is a simple AuthorizeAttribute
class you can use to decorate any actions which expect to receive JSON:
public class JsonRequestAttribute : AuthorizeAttribute
{
/*
*
* CONFIRM that this is REALLY a JSON request.
* This will mitigate the risk of a CSRF attack
* which masquerades an "application/x-www-form-urlencoded" request
* as a JSON request
*
*/
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// This request is masquerading as a JSON request, kill it.
JsonResult unauthorizedResult = new JsonResult();
unauthorizedResult.Data = "Invalid request";
unauthorizedResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
filterContext.Result = unauthorizedResult;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With