La mejor manera de manejar la seguridad y evitar XSS con las URL ingresadas por el usuario

StackOverflow https://stackoverflow.com/questions/205923

Pregunta

Tenemos una aplicación de alta seguridad y queremos permitir a los usuarios ingresar URL que otros usuarios verán.

Esto introduce un alto riesgo de hackeos XSS: un usuario podría ingresar javascript que otro usuario terminaría ejecutando.Dado que tenemos datos confidenciales, es esencial que esto nunca suceda.

¿Cuáles son las mejores prácticas para lidiar con esto?¿Es suficiente alguna lista blanca de seguridad o patrón de escape por sí solo?

Cualquier consejo sobre cómo lidiar con las redirecciones (mensaje "este enlace sale de nuestro sitio" en una página de advertencia antes de seguir el enlace, por ejemplo)

¿Existe algún argumento para no admitir ningún enlace ingresado por el usuario?


Aclaración:

Básicamente nuestros usuarios quieren ingresar:

stackoverflow.com

Y enviarlo a otro usuario:

<a href="http://stackoverflow.com">stackoverflow.com</a>

Lo que realmente me preocupa es que usen esto en un truco XSS.Es decir.ellos ingresan:

alerta('¡pirateado!');

Entonces otros usuarios obtienen este enlace:

<a href="alert('hacked!');">stackoverflow.com</a>

Mi ejemplo es solo para explicar el riesgo: soy muy consciente de que javascript y las URL son cosas diferentes, pero al permitirles ingresar las últimas, es posible que puedan ejecutar las primeras.

Te sorprendería saber cuántos sitios puedes dañar con este truco: HTML es aún peor.Si saben cómo manejar los enlaces, ¿también saben cómo desinfectarlos? <iframe>, <img> ¿Y referencias CSS inteligentes?

Estoy trabajando en un entorno de alta seguridad: un solo hackeo de XSS podría generar pérdidas muy elevadas para nosotros.Estoy feliz de poder producir una expresión regular (o usar una de las excelentes sugerencias hasta ahora) que podría excluir todo lo que se me ocurre, pero ¿sería suficiente?

¿Fue útil?

Solución

Si crees que las URL no pueden contener código, ¡piénsalo de nuevo!

https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

Lee eso y llora.

Así es como lo hacemos en Stack Overflow:

/// <summary>
/// returns "safe" URL, stripping anything outside normal charsets for URL
/// </summary>
public static string SanitizeUrl(string url)
{
    return Regex.Replace(url, @"[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]", "");
}

Otros consejos

El proceso de renderizar un enlace " safe " debe seguir tres o cuatro pasos:

  • Desactive / vuelva a codificar la cadena que le han dado (RSnake ha documentado varios trucos en http://ha.ckers.org/xss.html que usan escape y UTF codificaciones).
  • Limpie el enlace: las expresiones regulares son un buen comienzo: asegúrese de truncar la cadena o tirarla si contiene un " (o lo que sea que use para cerrar los atributos en su salida); Si está haciendo los enlaces solo como referencias a otra información, también puede forzar el protocolo al final de este proceso; si la parte anterior al primer colon no es 'http' o 'https', agregue 'http: //' al principio Esto le permite crear enlaces utilizables a partir de entradas incompletas, ya que un usuario escribiría en un navegador y le da una última oportunidad de tropezar con cualquier travesura que alguien haya intentado colarse.
  • Verifique que el resultado sea una URL bien formada (protocolo: //host.domain [: puerto] [/ ruta] [/ [archivo]] [? queryField = queryValue] [#anchor]).
  • Posiblemente verifique el resultado con una lista negra del sitio o intente obtenerlo mediante algún tipo de verificador de malware.

Si la seguridad es una prioridad, espero que los usuarios perdonen un poco de paranoia en este proceso, incluso si termina desechando algunos enlaces seguros.

Utilice una biblioteca, como OWASP-ESAPI API:

Lee lo siguiente:

Por ejemplo:

$url = "http://stackoverflow.com"; // e.g., 

Utilice una biblioteca, como OWASP-ESAPI API:

Lee lo siguiente:

Por ejemplo:

$url = "http://stackoverflow.com"; // e.g., 

Utilice una biblioteca, como OWASP-ESAPI API:

Lee lo siguiente:

Por ejemplo:

$url = "http://stackoverflow.com"; // e.g., 

Utilice una biblioteca, como OWASP-ESAPI API:

Lee lo siguiente:

Por ejemplo:

<*>

Otro ejemplo es usar una función incorporada. filter_var de PHP La función es un ejemplo:

<*>

Usando filter_var permite llamadas de javascript, y filtra esquemas que no son http ni https . Uso de OWASP ESAPI Sanitizer Es probablemente la mejor opción.

Otro ejemplo es el código de WordPress :

Además, dado que no hay forma de saber dónde se vincula la URL (es decir, podría ser una URL válida, pero el contenido de la URL podría ser malicioso), Google tiene un API de navegación segura a la que puede llamar:

Rodar su propia expresión regular para saneamiento es problemático por varias razones:

  • A menos que usted sea Jon Skeet, el código tendrá errores.
  • Las API existentes tienen muchas horas de revisión y prueba detrás de ellas.
  • Las API de validación de URL existentes consideran la internacionalización.
  • Las API existentes se mantendrán actualizadas con los estándares emergentes.

Otros temas a considerar:

  • ¿Qué esquemas permiten (son file: /// y telnet: // aceptables)?
  • ¿Qué restricciones desea colocar en el contenido de la URL (son aceptables las URL de malware)?
GET["user-homepage"]; $esapi = new ESAPI( "/etc/php5/esapi/ESAPI.xml" ); // Modified copy of ESAPI.xml $sanitizer = ESAPI::getSanitizer(); $sanitized_url = $sanitizer->getSanitizedURL( "user-homepage", $url );

Otro ejemplo es usar una función incorporada. filter_var de PHP La función es un ejemplo:

<*>

Usando filter_var permite llamadas de javascript, y filtra esquemas que no son http ni https . Uso de OWASP ESAPI Sanitizer Es probablemente la mejor opción.

Otro ejemplo es el código de WordPress :

Además, dado que no hay forma de saber dónde se vincula la URL (es decir, podría ser una URL válida, pero el contenido de la URL podría ser malicioso), Google tiene un API de navegación segura a la que puede llamar:

Rodar su propia expresión regular para saneamiento es problemático por varias razones:

  • A menos que usted sea Jon Skeet, el código tendrá errores.
  • Las API existentes tienen muchas horas de revisión y prueba detrás de ellas.
  • Las API de validación de URL existentes consideran la internacionalización.
  • Las API existentes se mantendrán actualizadas con los estándares emergentes.

Otros temas a considerar:

  • ¿Qué esquemas permiten (son file: /// y telnet: // aceptables)?
  • ¿Qué restricciones desea colocar en el contenido de la URL (son aceptables las URL de malware)?
GET["user-homepage"]; $sanitized_url = filter_var($url, FILTER_SANITIZE_URL);

Otro ejemplo es usar una función incorporada. filter_var de PHP La función es un ejemplo:

<*>

Usando filter_var permite llamadas de javascript, y filtra esquemas que no son http ni https . Uso de OWASP ESAPI Sanitizer Es probablemente la mejor opción.

Otro ejemplo es el código de WordPress :

Además, dado que no hay forma de saber dónde se vincula la URL (es decir, podría ser una URL válida, pero el contenido de la URL podría ser malicioso), Google tiene un API de navegación segura a la que puede llamar:

Rodar su propia expresión regular para saneamiento es problemático por varias razones:

  • A menos que usted sea Jon Skeet, el código tendrá errores.
  • Las API existentes tienen muchas horas de revisión y prueba detrás de ellas.
  • Las API de validación de URL existentes consideran la internacionalización.
  • Las API existentes se mantendrán actualizadas con los estándares emergentes.

Otros temas a considerar:

  • ¿Qué esquemas permiten (son file: /// y telnet: // aceptables)?
  • ¿Qué restricciones desea colocar en el contenido de la URL (son aceptables las URL de malware)?
GET["user-homepage"]; $esapi = new ESAPI( "/etc/php5/esapi/ESAPI.xml" ); // Modified copy of ESAPI.xml $sanitizer = ESAPI::getSanitizer(); $sanitized_url = $sanitizer->getSanitizedURL( "user-homepage", $url );

Otro ejemplo es usar una función incorporada. filter_var de PHP La función es un ejemplo:

<*>

Usando filter_var permite llamadas de javascript, y filtra esquemas que no son http ni https . Uso de OWASP ESAPI Sanitizer Es probablemente la mejor opción.

Otro ejemplo es el código de WordPress :

Además, dado que no hay forma de saber dónde se vincula la URL (es decir, podría ser una URL válida, pero el contenido de la URL podría ser malicioso), Google tiene un API de navegación segura a la que puede llamar:

Rodar su propia expresión regular para saneamiento es problemático por varias razones:

  • A menos que usted sea Jon Skeet, el código tendrá errores.
  • Las API existentes tienen muchas horas de revisión y prueba detrás de ellas.
  • Las API de validación de URL existentes consideran la internacionalización.
  • Las API existentes se mantendrán actualizadas con los estándares emergentes.

Otros temas a considerar:

  • ¿Qué esquemas permiten (son file: /// y telnet: // aceptables)?
  • ¿Qué restricciones desea colocar en el contenido de la URL (son aceptables las URL de malware)?

Solo HTMLEcode los enlaces cuando los genere. Asegúrese de no permitir enlaces javascript: . (Es mejor tener una lista blanca de protocolos que se acepten, por ejemplo, http, https y mailto.)

No especifica el idioma de su aplicación, presumiré ASP.NET, y para esto puede usar Microsoft Anti-Cross Site Scripting Library

Es muy fácil de usar, todo lo que necesitas es una inclusión y eso es :)

Mientras estás en el tema, ¿por qué no lees una lectura en Diseño Pautas para aplicaciones web seguras

Si cualquier otro idioma ... si hay una biblioteca para ASP.NET, tiene que estar disponible también para otro tipo de idioma (PHP, Python, ROR, etc.)

¿Qué tal si no los mostramos como un enlace? Solo usa el texto.

Combinado con una advertencia para proceder bajo su propio riesgo puede ser suficiente.

adición : consulte también ¿Debo limpiar el HTML? ¿Marcado para un CMS alojado? para una discusión sobre la eliminación de comentarios de usuarios

En mi proyecto escrito en JavaScript, uso esta expresión regular como lista blanca:

 url.match(/^((https?|ftp):\/\/|\.{0,2}\/)/)

la única limitación es que necesitas poner ./ delante de los archivos en el mismo directorio, pero creo que puedo vivir con eso.

Podría usar un código hexadecimal para convertir la URL completa y enviarla a su servidor. De esa manera el cliente no entendería el contenido a primera vista. Después de leer el contenido, puedes decodificar la URL del contenido =? y enviarlo al navegador.

Permitir una URL y permitir JavaScript son 2 cosas diferentes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top