¿Qué 'información confidencial' podría revelarse al configurar JsonRequestBehavior en AllowGet

112

Recibo el mismo error de siempre cada vez que pruebo un nuevo URLdesde la barra de direcciones de mi navegador cuando estoy returning Json(usando el integrado MVC JsonResult helper):

Esta solicitud se ha bloqueado porque la información confidencial podría divulgarse a sitios web de terceros cuando se utiliza en un GET request. Para permitir GET requests, establezca JsonRequestBehavioren AllowGet.

En lugar de gruñir en reconocimiento y encender Fiddler para hacer una solicitud de publicación, esta vez, me pregunto exactamente qué es lo que GETexpone una POSTsolicitud que una solicitud no.

A. Murray
fuente

Respuestas:

82

Supongamos que su sitio web tiene un GetUsermétodo web:

http://www.example.com/User/GetUser/32

que devuelve una respuesta JSON:

{ "Name": "John Doe" }

Si este método acepta solo solicitudes POST, entonces el contenido solo se devolverá al navegador si se realiza una solicitud AJAX http://www.example.com/User/GetUser/32mediante el método POST. Tenga en cuenta que, a menos que haya implementado CORS , el navegador protegerá los datos de otros dominios que realicen esta solicitud al suyo.

Sin embargo, si permitió las solicitudes GET, además de realizar una solicitud AJAX similar a la anterior con GET en lugar de POST, un usuario malintencionado podría incluir su JSON en el contexto de su propio sitio mediante el uso de una scriptetiqueta en el HTML. por ejemplo, en www.evil.com:

<script src="http://www.example.com/User/GetUser/32"></script>

Este JavaScript debería ser inútil www.evil.comporque no debería haber forma de leer el objeto devuelto por su método web. Sin embargo, debido a errores en las versiones antiguas de los navegadores (por ejemplo, Firefox 3), es posible redefinir los objetos prototipo de JavaScript y hacer posible la www.evil.comlectura de los datos devueltos por su método. Esto se conoce como secuestro de JSON.

Consulte esta publicación para conocer algunos métodos para prevenir esto. Sin embargo, no es un problema conocido con las versiones posteriores de los navegadores modernos (Firefox, Chrome, IE).

SilverlightFox
fuente
25
Buena publicación, pero si incluye una etiqueta [Autorizar] en el controlador, no debe preocuparse por la seguridad. Espero que este código ayude a alguien, Json (returnMsg, JsonRequestBehavior.AllowGet)
Dhanuka777
17
@ Dhanuka777: Desafortunadamente, no es cierto. Los ataques CSRF podrían ser posibles si el método tiene efectos secundarios (por ejemplo www.example.com/User/DeleteUser/32), ya que la solicitud incluirá las cookies necesarias para la autenticación, ya que provienen de la máquina de la víctima. [Authorize]tampoco lo salvará del ataque que se detalla aquí en el caso de un navegador muy antiguo: es el propio usuario quien lo visita, www.evil.compor lo que la solicitud que www.evil.comrealiza www.example.comcontendrá la cookie de autorización.
SilverlightFox
1
Y si la acción tiene algún efecto secundario, nunca debe invocarse con el método GET; la convención es usar GET solo para leer los datos y todas las operaciones de efectos secundarios deben usar POST, PUT, DELETE, etc. En otras palabras, yo simplemente piense que este mensaje de error de "información confidencial" es engañoso. Si el desarrollador usa el método GET de la forma en que debería usarse, ¡todo está bien! :)
ps_ttf
1
Todavía no estoy seguro de qué diferencia hace. No es como si la publicación estuviera más protegida o encriptada que get. Sigue siendo solo texto sin formato. Puedo enviar una solicitud tan fácilmente como publicar a través de cualquier herramienta y aún así obtener la misma información de texto sin formato. Un usuario malintencionado podría escribir fácilmente cualquier código del lado del servidor en su propio sitio para hacer una publicación también.
computrius
1
@Castrohenge: No, porque esto requiere que se establezca un encabezado que no se enviará con la solicitud GET para el script src.
SilverlightFox
111

en su devolución utilice lo siguiente:

return this.Json("you result", JsonRequestBehavior.AllowGet);
OldTrain
fuente
7
¿Cómo responde esto realmente a la pregunta del PO? Todo lo que hace esta respuesta es decirles a todos cómo sortear la excepción ..
eaglei22
2
Sí, úsalo ... Es como intentar atrapar con una captura vacía. NO use a estos chicos (antes de que comprenda los riesgos). -1'd
sotn
6
Es irresponsable decirle a la gente que ignore una advertencia de seguridad sin al menos explicar las consecuencias. -1
Eduardo Wada
58

De forma predeterminada, el marco ASP.NET MVC no le permite responder a una solicitud GET con una carga útil JSON, ya que existe la posibilidad de que un usuario malintencionado pueda obtener acceso a la carga útil a través de un proceso conocido como secuestro de JSON. No desea devolver información confidencial utilizando JSON en una solicitud GET.

Si necesita enviar JSON en respuesta a un GET y no está exponiendo datos confidenciales, puede permitir explícitamente el comportamiento pasando JsonRequestBehavior.AllowGetcomo un segundo parámetro alJson método.

Como

  [HttpGet] //No need to decorate, as by default it will be GET
  public JsonResult GetMyData(){  
    var myResultDataObject = buildMyData(); // build, but keep controller thin
    // delegating buildMyData to builder/Query Builder using CQRS makes easy :)
    return Json(myResultDataObject, JsonRequestBehavior.AllowGet);
  }

Aquí hay un artículo interesante de Phil Haack JSON Hijackingsobre por qué no usar Json con el método GET

Murali Murugesan
fuente
2
Buena publicación. Buena razón por la que debería utilizar HTTPS.
pqsk
6
No creo que HTTPS ayude aquí.
Sean McMillan
10

Cuando queremos devolver un objeto json al cliente desde la aplicación MVC, debemos especificar explícitamente JsonRequestBehavior.AllowGet al devolver un objeto. Como resultado, devuelvo los datos json de la siguiente manera para solucionar el problema:

    return Json(yourObjectData, JsonRequestBehavior.AllowGet);
Loc Huynh
fuente
7

Debe usar JsonRequestBehavior.AllowGet para la respuesta Json de esta manera:

return Json(YourObject, JsonRequestBehavior.AllowGet);
keivan kashani
fuente
0

return Json ("Éxito", JsonRequestBehavior.AllowGet)

Pergin Sheni
fuente