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.
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 .
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.
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 .
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 .
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 trinity4: 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
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.
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.