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 开发者_Go百科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?
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;
}
}
}
精彩评论