HTML 5 y sus nuevos tags de <audio>
y <video>
terminaron desencadenando anoche, una batalla campal con mis neuronas.
A raíz de querer incorporar audio OGG en una de mis Webs, descubrí que si el audio estaba alojado en mi servidor, no se reproducía. En cambio, si modificaba la ruta del archivo de audio colocando una URI externa, el audio se reproducía sin problemas.
De allí en más, comencé a investigar si era necesario que el servidor tuviese algún requisito/configuración/cuidado/whatever para permitir la reproducción de audio. Hasta incluso, pedí ayuda por Twitter con la esperanza de que a alguien se le prendiese la lamparita y muchísimas personas colaboraron. Sin embargo, cuando hallé la respuesta final, me di cuenta que era mucho más compleja de lo que me esperaba.
El problema
- Intentando acceder a la URL del archivo de audio, éste era loclizado y sin embargo no se podía acceder a él.
- Con wget el archivo bajaba sin inconvenientes;
- Con los navegadores Firefox, Chrome y Chromium (desde Ubuntu GNU/Linux) podía reproducir audio en el mismo formato sin inconvenientes, siempre y cuando estos archivos NO se encontrasen en mi servidor.
Contexto
Se trataba de un servidor Ubuntu 12.04, con Apache 2.2 y… ModSecurity instalado con el paquete de reglas de OWASP. Mi mayor sospecha estaba sobre estas últimas. Ya habíamos hablado la noche anterior con Dabo, sobre los falsos positivos de ModSecurity.
El camino hacia la solución
A través de Twitter, @mjimeneznet me explicaba que con solo los tags debería funcionar y que el server no necesitaba nada más. Lo mismo sobre los tags, mencionaba todo el mundo! Pero esto iba más allá de HTML 5. Había algo en el servidor, eso era seguro.
Y así fue que a @elrevo, @daviddfr, @hernanJ y @f_rojas se les ocurrió que podría ser necesario indicar los tipos MIME en Apache, ya sea a través de Virtual Host, en apache2.conf
directamente o en .htaccess
.
Tras agregar al VirtualHost un AddType
con el formato ogg, probé y solo en Firefox, parecía haberse resuelto el problema. Sin embargo, en Chrome y Chromium aún seguía el fallo.
En eso apareció @MatiasKatz con quien desde Google Talk, estuvimos haciendo varias pruebas. Hasta que se me ocurrió mirar los logs de error de Apache. Hice un tail -f
a los logs, y allí estaban «esperándome» esos «malditos»:
[Sat Dec 07 23:15:03 2013] [error] [client XXX.XXX.XXX.XXX]
<strong>ModSecurity: Access denied with code 403</strong>
(phase 2). String match "bytes=0-" at REQUEST_HEADERS:Range.
[<strong>file "/etc/modsecurity/base_rules/modsecurity_crs_20_protocol_violations.conf</strong>"]
[<strong>line "248"</strong>] [id "958291"] [rev "2.2.5"]
[msg "Range: field exists and begins with 0."] [data "bytes=0-"]
[<strong>severity "NOTICE"</strong>] [tag "RULE_MATURITY/5"]
[tag "RULE_ACCURACY/7"]
[tag "https://www.owasp.org/index.php/ModSecurity_CRS_RuleID-958291"]
[tag "PROTOCOL_VIOLATION/INVALID_HREQ"]
[tag "http://www.bad-behavior.ioerror.us/documentation/how-it-works/"]
[hostname "www.originalhacker.org"] [<strong>uri "/Fenster.ogg"</strong>]
[unique_id "UqOr98bHXb0AAHj4CSkAAAAF"]
Este error se replicaba decenas de veces. Resaltado en negritas vemos:
- ModSecurity negaba el acceso con un error 403;
- La causa era el archivo de reglas crs_20 sobre violaciones de protocolo;
- La regla específica era la indicada en la línea 248 (vale aclarar que muchas veces, se edita la regla en cuestión y es otra la que prohíbe el acceso así que esto era para ser tomado con pinzas)
- La severidad del supuesto ataque evitado, era a penas un aviso (notice)
- Finalmente, la URI, era la de mi famoso archivo de audio Fenster.ogg
La parte más desagradable era que ninguna de las URL logueadas, era accesible, así que en principio, no tenía explicación ni justificación para esa regla.
Lo primero que hice para verificar si era o no ModSecurity quien me estaba jodiendo, fue mover el archivo a un directorio de pruebas a fin de eliminarlo de su origen pero mantenerlo en copia de resguardo. Reinicié Apache y el problema desapareció. Finalmente, solo comenté la regla en cuestión y volví a reiniciar Apache.
La solución
En el archivo de reglas modsecurity_crs_20_protocol_violations.conf
comentar la regla de línea 248:
#SecRule REQUEST_HEADERS:Range "@beginsWith bytes=0-" "phase:2,
rev:'2.2.5',t:none,block,msg:'Range: field exists and begins with 0.',
logdata:'%{matched_var}',severity:'5',id:'958291',tag:'RULE_MATURITY/5',
tag:'RULE_ACCURACY/7',tag:'https://www.owasp.org/index.php/ModSecurity_CRS_RuleID-%{tx.id}',
tag:'PROTOCOL_VIOLATION/INVALID_HREQ',
tag:'http://www.bad-behavior.ioerror.us/documentation/how-it-works/',
setvar:'tx.msg=%{rule.msg}',setvar:tx.id=%{rule.id},
setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},
setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},
setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}"
Reiniciar Apache y ¡problema resuelto!
La explicación a todo
Erradicar un error pero no encontrarle la explicación lógica es como estar co….
(por si no se entendió mi metáfora: lo anterior fue un ejemplo de algo que te deja con una sensación de discontinuidad y por consiguiente, de algo inconcluso xD)
Así que para no quedarme con esa asquerosa sensación, a pesar de haber resuelto el problema, seguí analizando lo sucedido hasta hallar respuestas y el tema es así:
- En el archivo de reglas de OWASP, las líneas previas a la regla que se comentó, explicaban de manera abreviada, que la misma era en cumplimiento con lo establecido en las definiciones RFC 2616 (correspondiente a la definición de estándares del protocolo HTTP 1.1);
- Los estándares HTTP están publicados nada más ni nada menos que por la W3C;
- En dicha RFC, la sección 14.35.1 se refiere a los rangos de bytes que el cliente (navegador en este caso) envía en los campos de cabecera al servidor (a.k.a «headers» para los amigos). Es decir que la sección 14.35.1 de las RFC 2616 son las que definen los estándares para los rangos de bytes enviados por el cliente al servidor a través de las cabeceras HTTP;
- Estas especificaciones, dicen claramente que: «si un rango de bytes sintácticamente válido, cuyo primer byte del rango sea menor a la longitud total del elemento a ser servido, o por lo menos, el sufijo del intervalo es distinto que cero, entonces la solicitud puede ser satisfecha por el servidor, pero de lo contrario, el servidor debe rechazar la petición«;
Si volvemos a darle un vistazo al error que ModSecurity grabó en los logs, veremos esto:
ModSecurity: Access denied with code 403 (phase 2).
String match "<strong>bytes=0-</strong>" at REQUEST_HEADERS:Range
El valor recibido indicaba un rango inválido en el cual, faltaba el sufijo del rango:
bytes=0-???
Recordemos que ese error, se producía al intentar acceder desde Google Chrome o desde su fork libre Chromium, al archivo de audio ogg. Es decir, que tanto Google Chrome como Chromium, envían como valor de rango de bytes en los encabezados HTTP, un rango inválido (sin sufijo). Dicha solicitud VIOLA LOS ESTÁNDARES DE LAS RFC 2616.
Vale aclarar que:
- A raíz de esto, revisando los logs, me di cuenta que el reclamo realizado por muchos usuarios que eran rechazados al intentar descargar un PDF desde dispositivos con Android, también era a causa de este problema. Vale decir que Android tampoco cumple con dichos estándares.
- A pesar de haberme enojado con MpdSecurity, no se puede responsabilizar del bloqueo a las reglas de OWASP ni mucho menos a ModSecurity, puesto que es el Software de Google quien al incumplir con dichos estándares provoca que sus aplicaciones actúen de forma similar a como lo haría una herramienta pensada para el ataque.
Lamentablemente, por la irresponsabilidad de Google, la única solución (que en realidad sería utilizar Mozilla Firefox), fue comentar la regla mencionada.
Happy Hacking, Fuckin’ Google!
Dedicado con todo googlelove a mi compañero Debish 😛
7 ideas sobre “Problemas al reproducir Ogg bajo Apache con ModSecurity desde Chrome y Chromium”
Gracias, gracias, siempre es un honor que te dediquen una de las muchas cagadas que Google está cometiendo últimamente 😛
Por lo demás, muy buen artículo. De manifiesto la curiosidad del hacker que lleva a mover cielo y tierra hasta encontrar la respuesta.
Que verdad es que en estas cosas se sabe como se empieza, pero nunca como terminan.
Ya se lo decia yo a @Liamngls, ni chrome ni chromium, Firefox por siempre xD
Excelente el dato Euge, gracias 😉
Muchas gracias por el articulo, interesante saber esto
Este es el típico post que si no te ha pasado antes algo así, ni te planteas que pueda ser por una regla de Mod Sec que esté tocando las pelotas.
Gracias Euge por compartirlo, no veas qué sensación me entró cuando aún dos días antes grabando el podcast hablamos del tema xDD. Así que amigos ya sabéis, si Mod Sec está rulando, las reglas hay que estar mirando -:P
(Yo tengo organizados unos autobloqueos con Mod Sec de los de contar xD)
Un abrazo !
Muchas gracias Eugenia, siempre hay mucho que aprender en tus publicaciones.
Saludos.
La verdad es que yo identifiqué rápidamente que era un problema relacionado con las reglas de OWASP, pero no me gusta desactivar reglas sin un verdadero propósito justificado. Después de buscar, tu post me ha resuelto la duda… aunque se me ha quedado la espinita clavada como a ti, que no es la mejor solución, aunque no haya alternativa.
De todas formas, yo recomiendo en vez de comentar la línea en el fichero de OWASP, es desactivar el ID de la regla en los sites que desees, o en general en una lista de whitelist que tengas, tal que así:
SecRuleRemoveById 958291
De esta manera, si actualizas los ficheros de OWASP, evitas que se vuelva a activar dicha regla, y si lo indicas en el VirtualHost correspondiente, evitas desactivar esa regla de manera general que puede ser util a otros Sites que no tienen que tener incompatibilidad.