El despropósito II parte

Amigo @eiximenis, me vas a permitir que en este post te llame como te mereces Sr. Don Eduard Tomas i Avellana y no es por hacerte la pelota, sino más bien por felicitarte por ese gran post.

Sobre WebApi, cookies y CSRF

En respuesta a este otro post mío.

Una evidencia, una fricada y un despropósito

Pero claro llego el momento de dejar los elogios, para empezar a darte cera de la buena Lengua fuera.

Si te tuviera que calificar, según lo que expones en el post optaría por evaluar dos cosas.

1. Seguridad. La nota para ese DelegatingHandler es un 10, si quieras que te sea sincero, estuve mirando esa posibilidad puesto que estas propuestas no me terminaron de convencer, dado que puedes tener algún problema de XSS y tu token puede ser vulnerable a robos y por tanto mala solución es.

Preventing CSRF Hacks in ASP.NET WebAPI

Preventing Cross-Site Request Forgery (CSRF) Attacks

Cosa que en MVC ese robo es bastante complicado puesto que va en un hidden y la única forma de acceder a el por parte de un usuario malicioso es hacer una petición GET desde un IFrame, pero en la actualidad como bien sabes los exploradores prohíben el acceso al contentDocument de un IFrame, menos mal.

Aunque algún intento con SVG FILTERS me consta que se ha hecho.

PIXEL PERFECT TIMING ATTACKS WITH HTML5

Que cosas fueron las que me decidieron no utilizar Referrer.

Que cuando hice las pruebas de CSRF me di cuenta que Chrome enviaba la cabecera Origin además de la cabecera Referrer por contra Internet Explorer y Firefox solo enviaban Refererr. Eso me llevo a investigar y encontrarme con esto.

The Web Origin Concept

Si quieres que te sea sincero la apoyo frente al envió de Referrer puesto que como usuario salvaguarda bastante más mi privacidad ya que solo se envía protocolo dominio y puerto.

-Que existe un Meta referrer donde yo como administrador de una web lo puedo colocar y ningún explorador va enviar el Referrer y que no tiene otro objetivo que proteger la privacidad de mis usuarios.

<meta name=»referrer» content=»never»>

En tu defensa tengo que decir que dejas muy claro que nunca se utilice una WebApi que se autentique por Cookie para exponer a terceros.

solo debes permitir autenticación por cookies en tus servicios web api si y solo si, son servicios web api pensados para ser usados tan solo desde la propia aplicación web. Y si lo haces asegúrate de establecer algún mecanismo adicional de seguridad para evitar CSRF.

Si por algún caso no se cumple el punto anterior y optas como dices por implementar un mecanismo de seguridad para evitar CSRF.

Que pasa si WebApi esta en un extremo http y yo consumo tu api desde un protocolo https.

Pues te lo digo que jamás te va a llegar el Referrer.

HTTP referer lee atentamente el aparatado Referer hiding

a website is accessed from a HTTP Secure (HTTPS) connection and a link points to anywhere except another secure location, then the referer field is not sent.[9]

Si te fijas ese [9] te va a llevar a este otro link donde se expone muy claramente ese punto.

15.1.3 Encoding Sensitive Information in URI’s

 

-Que siguiendo con ese mismo punto otra cosa que se expone muy clara y que evidentemente no se cumple, es que todos los agentes de usuario deberían de exponer un mecanismo para activar y desactivar el envió de la cabecera http referrer.

Cosa que como es de suponer se incumple por parte de todos excepto por Firefox.

Browser Privacy: How to Disable HTTP Referer, como es negra y a alguno le puede dar miedo entrar os voy a copiar lo que dice la web.

Mozilla Firefox

1. Type about:config in the address bar and press Enter.

2. Find the entry that says Network.http.sendRefererHeader and double-click on it.

3. Set the entry to one of the following:

0 – Disable referrer. <— This is what you want to set it as
1 – Send the Referer header when clicking on a link, and set document.referrer for the following page.
2 – Send the Referer header when clicking on a link or loading an image.

Google Chrome

Google Chrome does not allow you to disable this through any of their own features. In order to disable your HTTP Referer in Chrome, I recommend an extension such as this one:https://chrome.google.com/webstore/d…llklmbakbphhll

Opera

You can disable the HTTP Referer so that the browser is not sending it with your HTTP requests. In Opera, go to opera:config#UserPrefs|EnableReferrer, then uncheck the box, and finally save.

Apple Safari

Use a different browser. Safari currently does not have any working plugins or extensions that can successfully do this. If anyone is aware of one that works, comment or send me a PM and I will test it on my iMac to confirm.

Internet Explorer

Use a different browser. Internet Explorer in itself is outdated, bulky, resource intensive, and lacks many features that come standard with most other browsers. And on top of that Microsoft has stated there is no way to disable HTTP Referer on Internet Explorer, nor do they intend to add such a feature.

Por todas estás cosas es por las que no me parece acertado utilizar referrer como mecanismo para prevenir CSRF

2. Privacidad. Visto los puntos anteriores es evidente que estás utilizando mi privacidad como usuario para garantizar la seguridad de tu aplicación y es por eso por lo que en este apartado te tengo que poner un buen cerapio “0” seguro que es el primero que sacas en tu vida Lengua fuera.

Así que para resumir tu post de ayer con el que estoy en casi todo de acuerdo menos en la utilización de Referrer no me queda otra que evaluarte con un Suficiente Pelado Sonrisa.

Resumiendo que soy partidario de quitar los MediatypeFormatter que soportan Content-Type:application/xxx-form-urlencoded y que no son otros que.

JQueryMvcFormUrlEncodedFormatter.

-FormUrlEncodedMediaTypeFormatter.

En definitiva que a partir de este momento voy a dejar mi WebApiConfig.cs que está en la carpeta App_Start de la siguiente forma.

   1: public static class WebApiConfig

   2:     {

   3:         public static void Register(HttpConfiguration config)

   4:         {

   5:             //http://www.dotnetcurry.com/showarticle.aspx?ID=890            

   6:  

   7:             // Si estás lineas no las ejecutas tu api va a permitir 

   8:             // Content-Type:application/xxx-form-urlencoded y por tanto si te autenticas

   9:             // por cookie tu aplicación va a ser vulnerable a ataques del tipo CSRF

  10:             // http://es.wikipedia.org/wiki/Cross_Site_Request_Forgery

  11:  

  12:             // Es decir que debes de implementar una estrategia CSRF en tu aplicación

  13:             //http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-(csrf)-attacks

  14:  

  15:             var removeFormaters = GlobalConfiguration.Configuration.Formatters

  16:                 .Where(x => x.GetType() == typeof(JQueryMvcFormUrlEncodedFormatter) || x.GetType() == typeof(FormUrlEncodedMediaTypeFormatter))

  17:                 .ToList();

  18:  

  19:             foreach (var formater in removeFormaters)

  20:             {

  21:                 GlobalConfiguration.Configuration.Formatters.Remove(formater);

  22:             }

  23:  

  24:             config.Routes.MapHttpRoute(

  25:                 name: "DefaultApi",

  26:                 routeTemplate: "api/{controller}/{id}",

  27:                 defaults: new { id = RouteParameter.Optional }

  28:             );

  29:  

  30:             // Quite los comentarios de la siguiente línea de código para habilitar la compatibilidad de consultas para las acciones con un tipo de valor devuelto IQueryable o IQueryable<T>.

  31:             // Para evitar el procesamiento de consultas inesperadas o malintencionadas, use la configuración de validación en QueryableAttribute para validar las consultas entrantes.

  32:             // Para obtener más información, visite http://go.microsoft.com/fwlink/?LinkId=279712.

  33:             //config.EnableQuerySupport();

  34:         }

  35:     }

Como creo que el público se merece conocer las técnicas con las que ayer intentamos tirar nuestros argumentos por tierra voy a hacer una pequeña descripción.

1. Evitar en el envió de Referrer.

   1: <script type="text/javascript">
   1:  

   2:     function post_without_referer() {

   3:         // POST request, WebKit & Firefox. Data, meta & form submit trinity

   4:         location = 'data:text/html,<html><meta http-equiv="refresh" content="0; url=data:text/html,' +

   5:                    '<form id=dynForm method=POST action='http://localhost:30022/api/prueba/'>' +

   6:                    '<input type=hidden name=email value=example@live.com />' +

   7:                    '<input type=hidden name=pass value=password />' +

   8:                    '<input type=hidden name=locale value=en_US />' +

   9:                    '</form><script>document.getElementById('dynForm').submit()</scri' + 'pt>"></html>';

  10:     }

  11:  

</script>

   2:  

   3: <a href="#" onclick="post_without_referer()" target="Hello">POST without referer (FF,chrome)</a>

Lo que hace es cambiar el location y solo funciona en FF y Chrome. Aunque algo parecido se puede hacer en IE con un anchor estableciendo rel=”noreferrer” y href a algo como esto

image

Os he pasado todas las instrucciones que he generado desde la consola del navegador y si queréis ver que pasa mandaros un email con este anchor a vosotros mismos.

Viendo el código de Eduard para el DelegatingHandler es evidente que no cuela ninguna de estas técnicas, es decir su código es seguro.

2. Eduard me defendía que “application/json” también podía ser susceptible de ataques CSRF según esta documentación.

W3C HTML JSON form submission

Espero que eso no se apruebe en la vida, porque entonces la fiesta va a ser buena y hasta donde he probado no lo soporta ningún explorador.

Ojo que no estás inmune con “application/json”. Es decir que si habilitas CORS y te autenticas por Api no solo te pueden hacer CSRF a los métodos POST sino a todos, pero esto lo vamos a dejar para otro capítulo o para que lo investigues tu.

3. Basándome en esos dos MediaTyperFormatter que aportan más problemas que beneficios yo le comente que porque no creamos un MediaTypperFormatter que soporte “text/plain” y después deserializamos con Json.Net.

Sabes lo que te puede pasar, pues sencillo que te puedo enviar lo siguiente.

   1: <form enctype="text/plain" method="post" action="/Home/Test">

   2:     <input name='{"a":1,"b":{"c":3}, "ignore_me":"' value='test"}'type='hidden'>

   3:     <input type="submit" value="send" /> 

De momento WebApi lanza un error porque no soporta “text/plain” espero que a nadie se le ocurra.

Para finalizar, está claro que esto es responsabilidad tuya y solamente tuya, no es del Framework, aunque este no te lo pone nada fácil y es por eso por lo que para mi es un despropósito.

Hazte las siguientes preguntas.

1. Porque la generación de un controlador MVC y WebApi no generan un mecanismo anti CSRF o por lo menos lo preguntan.

2. Porque se agregan esos dos MediaTypeFormatter de serie y sin más advertencias y que en el 99% de los casos no los voy a utilizar y son un problema con respecto a seguridad.

Conclusión.

Piénsate muy mucho la autenticación por Cookies en tu WebApi.

 

 

 

 

3 comentarios sobre “El despropósito II parte”

  1. Buenas Pedro…
    Por alusiones 😛

    1. Usar origin es mucho más elegante que referrer pero tiene el problema que comentas: referrer lo usan todos los navegadores y origin no. Es cierto que referrer es más intrusivo a nivel de privacidad. Pero no perdamos de vista el escenario: Queremos evitar CSRF en unos controladores webapi que forman parte de MI aplicación. Los voy a llamar solo desde MI aplicación. En este caso, dado que nunca se llaman desde fuera, referrer no invade realmente la privacidad. Si desactivar referrer fuese algo extendido en todos los navegadores, entonces pues o bien se tiene que decir al usuario que la web requiere que esté habilitado (como se hace con las cookies, que son quizá más intrusivas aún) o bien buscar otro mecanismo de seguridad (un token que también tienen sus propios problemas adicionales).
    Referrer es sencillo y funciona relativamente bien. Lo importante es NO aceptar peticiones sin referrer porque como tu dices entonces si que hay varias puertas abiertas.

    Los distintos casos que comentas (la etiqueta y el salto de http a https) no me parecen relevantes para este escenario en concreto: dado que son controladores para ser usados SOLO desde mi web, en mi web yo no meteré dicha meta y evitaré siempre saltos de http a https y viceversa. Todo arreglado 😛

    De todos modos lo importante es que la gente se de cuenta de que puede pasar esto. Si conseguimos eso con esos POSTs perfecto!

    2. Sobre el tema de los formatters: ahí tienes toda la razón. No puse el énfasis necesario en mi post. Lo que abre la puerta al ataque CSRF es la autenticación por cookies, lo que hace que dicho ataque sea un juego de niños es soportar el content-type application/xxx-form-urlencoded. Sin esos dos formatters todo se complica ciertamente. Quizá hubiese sido mejor que por defecto no estuviesen. Pero tengo la impresión que están para facilitar las llamadas usando ajax. Aunque enviar un JSON usando ajax es muy sencillo, también, o sea que…
    Por lo que bueno… entiendo que el título del despropósito va por aplicar por defecto esos dos formatters, pero vamos, si no fuese así estaría media internet quejándose de que un POST a un controlador web api no funciona. Y la gente terminaría usando un controlador MVC! xDD

    Buena discusión Pedro!!

  2. Simplemente por este comentario defendiendo tus argumentos he de decir que ese Suficiente pelado y dado tu compartamiento,
    es merecedor de Matricula de Honor.

    Pero piensa que el que va a poner el meta

    Soy yo, pero tu perfección en el código hace que me lo coma con patatas!!!

    Gracias por estos momentos que hacen falta:)

    La verda que esta trilogía de las diosas habría que llevarla a este sitio

    http://social.msdn.microsoft.com/Forums/es-ES/70492345-424a-49e8-b63c-828f8b122e41/actualizar-solo-una-parte-de-la-vista-con-ajax-desde-controller-en-mvc-4?forum=aspnetmvces

    Y responderle a los dos, o mejor dejarla como lee antes y después pregunta cosa que haría feliz a nuestro gran amigo

    Don Lluis Franco’s Corner que ha luchado hasta la saciedad por el bien de los foros MSDN.

    Grandes los dos y….

    Moltes Gràcies

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *