407
votes

Why is Json Request Behavior needed?

If I want to restrict the HttpGet requests to my action I can decorate the action with the [HttpPost] attribute

Example:

[HttpPost]
public JsonResult Foo()
{
    return Json("Secrets");
}

// Instead of:
public JsonResult Foo()
{
    return Json("Secrets", JsonRequestBehavior.AllowGet);
}

Why isn't [HttpPost]sufficient?
Why the framework "bugs" us with the JsonRequestBehavior.AllowGet for every JsonResult that we have. If I want to deny get requests I'll add the HttpPost attribute.

5
Very similar to stackoverflow.com/questions/1625671/… (although I found this one searching for my own question :))Jedidja
Because GET is supposed to be idempotent whereas POST is not. By making GETs -> POSTs, you change the semantics of the interface.rism
Because your code would look too clean if you didn't have to add crufty args everywhere.John Shedletsky

5 Answers

286
votes

MVC defaults to DenyGet to protect you against a very specific attack involving JSON requests to improve the liklihood that the implications of allowing HTTP GET exposure are considered in advance of allowing them to occur.

This is opposed to afterwards when it might be too late.

Note: If your action method does not return sensitive data, then it should be safe to allow the get.

Further reading from my Wrox ASP.NET MVC3 book

By default, the ASP.NET MVC framework does not allow you to respond to an HTTP GET request with a JSON payload. If you need to send JSON in response to a GET, you'll need to explicitly allow the behavior by using JsonRequestBehavior.AllowGet as the second parameter to the Json method. However, there is a chance a malicious user can gain access to the JSON payload through a process known as JSON Hijacking. You do not want to return sensitive information using JSON in a GET request. For more details, see Phil's post at http://haacked.com/archive/2009/06/24/json-hijacking.aspx/ or this SO post.

Haack, Phil (2011). Professional ASP.NET MVC 3 (Wrox Programmer to Programmer) (Kindle Locations 6014-6020). Wrox. Kindle Edition.

Related StackOverflow question

With most recents browsers (starting with Firefox 21, Chrome 27, or IE 10), this is no more a vulnerability.

62
votes

To make it easier for yourself you could also create an actionfilterattribute

public class AllowJsonGetAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var jsonResult = filterContext.Result as JsonResult;

        if (jsonResult == null)
            throw new ArgumentException("Action does not return a JsonResult, 
                                                   attribute AllowJsonGet is not allowed");

        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;            

        base.OnResultExecuting(filterContext);
    }
}

and use it on your action

[AllowJsonGet]
public JsonResult MyAjaxAction()
{
    return Json("this is my test");
}
8
votes

By default Jsonresult "Deny get"

Suppose if we have method like below

  [HttpPost]
 public JsonResult amc(){}

By default it "Deny Get".

In the below method

public JsonResult amc(){}

When you need to allowget or use get ,we have to use JsonRequestBehavior.AllowGet.

public JsonResult amc()
{
 return Json(new Modle.JsonResponseData { Status = flag, Message = msg, Html = html }, JsonRequestBehavior.AllowGet);
}
6
votes

Improving upon the answer of @Arjen de Mooij a bit by making the AllowJsonGetAttribute applicable to mvc-controllers (not just individual action-methods):

using System.Web.Mvc;
public sealed class AllowJsonGetAttribute : ActionFilterAttribute, IActionFilter
{
    void IActionFilter.OnActionExecuted(ActionExecutedContext context)
    {
        var jsonResult = context.Result as JsonResult;
        if (jsonResult == null) return;

        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var jsonResult = filterContext.Result as JsonResult;
        if (jsonResult == null) return;

        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
        base.OnResultExecuting(filterContext);
    }
}
3
votes

You do not need it.

If your action has the HttpPost attribute, then you do not need to bother with setting the JsonRequestBehavior and use the overload without it. There is an overload for each method without the JsonRequestBehavior enum. Here they are:

Without JsonRequestBehavior

protected internal JsonResult Json(object data);
protected internal JsonResult Json(object data, string contentType);
protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding);

With JsonRequestBehavior

protected internal JsonResult Json(object data, JsonRequestBehavior behavior);
protected internal JsonResult Json(object data, string contentType, 
                                   JsonRequestBehavior behavior);
protected internal virtual JsonResult Json(object data, string contentType, 
    Encoding contentEncoding, JsonRequestBehavior behavior);