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


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

Esto introduce un alto riesgo de hacks XSS - un usuario podría potencialmente entrar en javascript que otro usuario termina ejecutando. Dado que tenemos datos confidenciales, es esencial que esto nunca suceda.

¿Cuáles son las mejores prácticas para hacer frente a esto? ¿Es suficiente alguna lista blanca de seguridad o patrón de escape?

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

¿Hay algún argumento para no admitir enlaces introducidos por el usuario en absoluto?


Aclaración:

Básicamente nuestros usuarios quieren introducir:

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 hack de XSS. I. e. they input:

Alerta ('hacked!');

So 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 estas últimas pueden ser capaces de ejecutar las primeras.

Usted se sorprendería de cuántos sitios se puede romper con este truco - HTML es aún peor. Si saben tratar con enlaces, también saben desinfectar <iframe>, <img> y referencias CSS inteligentes?

Estoy trabajando en un entorno de alta seguridad - un solo hack XSS podría resultar en pérdidas muy altas 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?

Author: Keith, 2008-10-15

8 answers

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+&@#/%?=~_|!:,.;\(\)]", "");
}
 46
Author: Jeff Atwood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-16 12:26:16

El proceso de hacer un enlace "seguro" debe pasar por tres o cuatro pasos:

  • Unescape / re-codificar la cadena que se le ha dado (RSnake ha documentado una serie de trucos en http://ha.ckers.org/xss.html que usan escape y codificaciones UTF).
  • Limpie el enlace: Las expresiones regulares son un buen comienzo - asegúrese de truncar la cadena o tirarla si contiene un " (o lo 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 punto no es 'http' o 'https', agregue 'http://' al inicio. Esto le permite crear enlaces utilizables a partir de una entrada incompleta como un usuario escribiría en un navegador y le da una última oportunidad de tropezar con cualquier travesura que alguien haya tratado de colarse.
  • Compruebe que el resultado es una URL bien formada (protocolo://host.domain[:puerto][/camino][/[archivo]][?queryField=queryValue] [#anchor]).
  • Posiblemente verifique el resultado en una lista negra del sitio o intente recuperarlo a través de algún tipo de comprobador de malware.

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

 12
Author: Bell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-16 20:08:37

Use una biblioteca, como OWASP-ESAPI API:

Lea el siguiente:

Por ejemplo:

$url = "http://stackoverflow.com"; // e.g., $_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 integrada. La función de PHP filter_var es un ejemplo:

$url = "http://stackoverflow.com"; // e.g., $_GET["user-homepage"];
$sanitized_url = filter_var($url, FILTER_SANITIZE_URL);

Utilizando filter_var permite llamadas a javascript y filtra esquemas que no son ninguno de los dos http ni https. Usar el desinfectante OWASP ESAPI 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 enlaza la URL (es decir, podría ser una URL válida, pero el contenido de la URL podría ser travieso), Google tiene una API de navegación segura que puede llamada:

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

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

Otras cuestiones a considerar:

  • ¿Qué esquemas permitís (son file:/// y telnet:// aceptables)?
  • ¿Qué restricciones desea colocar en el contenido de la URL (son aceptables las URL de malware)?
 8
Author: Dave Jarvis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-01 22:10:20

Simplemente codifique los enlaces en HtmlEncode cuando los genere. Asegúrate de no permitir enlaces javascript:. (Es mejor tener una lista blanca de protocolos que se aceptan, por ejemplo, http, https y mailto.)

 3
Author: Patrick McElhaney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-19 21:14:40

Usted no especifica el idioma de su solicitud, entonces asumiré ASP.NET, y para esto se puede utilizar el Microsoft Anti-Cross Site Scripting Library

Es muy fácil de usar, todo lo que necesita es un include y eso es todo:)

Ya que estás en el tema, ¿por qué no leer en Directrices de diseño 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 lenguaje (PHP, Python, ROR, etc)

 3
Author: balexandre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-15 19:04:22

¿Qué tal no mostrarlos como un enlace? Solo usa el texto.

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

Adición - ver también ¿Debo desinfectar el marcado HTML de un CMS alojado? para una discusión sobre la desinfección de la entrada del usuario

 1
Author: warren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:33:26

Puede 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, podría decodificar la URL de contenido=? y enviarlo al navegador.

 -1
Author: Shashi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-26 08:14:19

Permitir una URL y permitir JavaScript son 2 cosas diferentes.

 -7
Author: Nick Stinemates,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-15 18:48:21