php - sirve - tipos de desinfeccion
¿Son estas dos funciones excesivas para la desinfección? (7)
Bueno, si no quieres reinventar la rueda puedes usar HTMLPurifier . Le permite decidir exactamente lo que quiere y lo que no quiere y evita los ataques XSS y tal
function sanitizeString($var)
{
$var = stripslashes($var);
$var = htmlentities($var);
$var = strip_tags($var);
return $var;
}
function sanitizeMySQL($var)
{
$var = mysql_real_escape_string($var);
$var = sanitizeString($var);
return $var;
}
Obtuve estas dos funciones de un libro y el autor dice que al usar estas dos, puedo estar más seguro contra XSS (la primera función) y las inyecciones de sql (segundo func). ¿Son todos esos necesarios?
También para desinfectar, utilizo declaraciones preparadas para evitar inyecciones de sql.
Lo usaría así:
$variable = sanitizeString($_POST[''user_input'']);
$variable = sanitizeMySQL($_POST[''user_input'']);
EDITAR: Deshazte de strip_tags para la primera función porque no hace nada. ¿Sería suficiente usar estas dos funciones para evitar la mayoría de los ataques y estar bien para un sitio público?
Es cierto, pero este nivel de escape puede no ser apropiado en todos los casos. ¿Qué sucede si quiere almacenar HTML en una base de datos?
Las mejores prácticas dictan que, en lugar de escapar al recibir valores, debe escapar de ellos cuando los muestre. Esto le permite representar tanto el HTML de la base de datos como el no HTML de la base de datos, y de todos modos es realmente a donde corresponde este tipo de código.
Otra ventaja de desinfectar el HTML saliente es que se puede descubrir un nuevo vector de ataque, en cuyo caso desinfectar el HTML entrante no hará nada para los valores que ya están en la base de datos, mientras que la sanitización saliente se aplicará retroactivamente sin tener que hacer nada especial.
Además, tenga en cuenta que strip_tags
en su primera función probablemente no tendrá ningún efecto, si todos los <
y >
han convertido en <
y >
.
Está haciendo htmlentities
(que convierte todo >
en >
) y luego llama a strip_tags
que en este momento no logrará nada más, ya que no hay etiquetas.
Para ser sincero, creo que el autor de estas funciones no tiene ni idea de qué son las inyecciones de XSS y SQL o qué hace exactamente la función utilizada.
Solo para nombrar dos rarezas:
- El uso de
stripslashes
después demysql_real_escape_string
elimina las barras añadidas pormysql_real_escape_string
. -
htmlentities
reemplaza los chatacters<
y>
que se usan enstrip_tags
para identificar etiquetas.
Además: en general, las funciones que protegen contra XSS no son adecuadas para proteger contra las inyecciones de SQL y viceversa. Porque cada idioma y contexto tiene sus propios caracteres especiales que deben ser atendidos.
Mi consejo es aprender por qué y cómo la inyección de código es posible y cómo protegerse de ella. Aprenda los idiomas con los que está trabajando, especialmente los personajes especiales y cómo escapar de estos.
Editar Aquí hay algunos ejemplos (probablemente extraños): imagine que permite que sus usuarios ingresen algún valor que deba usarse como un segmento de ruta en un URI que use en algún código JavaScript en un valor de atributo onclick
. Entonces, el contexto del lenguaje se ve así:
- Valor de atributo HTML
- Cadena de JavaScript
- Segmento de ruta URI
- Cadena de JavaScript
Y para hacerlo más divertido: está almacenando este valor de entrada en una base de datos.
Ahora, para almacenar este valor de entrada correctamente en su base de datos, solo necesita usar una codificación adecuada para el contexto en el que está a punto de insertar ese valor en el lenguaje de su base de datos (es decir, SQL); el resto no importa (todavía). Dado que desea insertarlo en una declaración de cadena SQL, los caracteres especiales contextuales son los caracteres que le permiten cambiar ese contexto. En cuanto a las declaraciones de cadenas, estos caracteres son (especialmente) los caracteres "
, ''
y "
''
que necesitan ser escapados. Pero como ya se dijo, las declaraciones preparadas hacen todo eso para usted, entonces úselas.
Ahora que tiene el valor en su base de datos, queremos mostrarlos correctamente. Aquí procedemos desde el contexto más interno al más externo y aplicamos la codificación adecuada en cada contexto:
- Para el contexto del segmento de ruta URI , necesitamos escapar (al menos) todos los caracteres que nos permiten cambiar ese contexto; en este caso
/
(dejar el segmento de camino actual)?
y#
(ambos dejan el contexto de ruta de URI). Podemos usarrawurlencode
para esto. - Para el contexto de cadena de JavaScript, debemos ocuparnos de
"
,''
y/
. Podemos usarjson_encode
para esto (si está disponible). - Para el valor del atributo HTML, tenemos que ocuparnos de
&
,"
,''
y<
. Podemos usarhtmlspecialchars
para esto.
Ahora todo junto:
''… onclick="''.htmlspecialchars(''window.open("http://example.com/''.json_encode(rawurlencode($row[''user-input''])).''")'').''" …''
Ahora si $row[''user-input'']
es "bar/baz"
la salida es:
… onclick="window.open("http://example.com/"%22bar%2Fbaz%22"")" …
Pero usar todas estas funciones en estos contextos no es exagerado. Porque aunque los contextos pueden tener caracteres especiales similares, tienen diferentes secuencias de escape. URI tiene la denominada codificación porcentual, JavaScript tiene secuencias de escape como /"
y HTML tiene referencias de caracteres como "
. Y no usar solo una de estas funciones permitirá romper el contexto.
Si está utilizando sentencias preparadas y marcadores de posición de SQL y nunca interpola la entrada del usuario directamente en sus cadenas de SQL, puede omitir completamente la desinfección de SQL.
Cuando utiliza marcadores de posición, la estructura de la instrucción SQL ( SELECT foo, bar, baz FROM my_table WHERE id = ?
) Se envía al motor de base de datos por separado de los valores de datos que (eventualmente) están vinculados a los marcadores de posición. Esto significa que, salvo errores importantes en el motor de la base de datos, no hay forma de que los valores de los datos sean malinterpretados como instrucciones SQL, por lo que brinda una protección completa contra los ataques de inyección de SQL sin necesidad de manipular sus datos para su almacenamiento.
No, esto no es excesivo, es una vulnerabilidad.
Este código es completamente vulnerable a la Inyección SQL. Estás haciendo mysql_real_escape_string () y luego estás haciendo stripslashes (). Entonces, "
se convertiría en /"
después de mysql_real_escape_string () y luego volvería a "
after the stripslashes (). Mysql_real_escape_string () solo es mejor detener la inyección sql. Las bibliotecas de consultas paramétricas como PDO y ADODB lo usan, y las consultas parametrizadas lo hacen muy fácil de detener por completo la inyección sql.
Prueba tu código:
$variable = sanitizeString($_POST[''user_input'']);
$variable = sanitizeMySQL($_POST[''user_input'']);
mysql_query("select * from mysql.user where Host=''".$variable."''");
Y si:
$_POST[''user_input''] = 1'' or 1=1 /*
Parcheado:
mysql_query("select * from mysql.user where Host=''".mysql_real_escape_string($variable)."''");
Este código también es vulnerable a algunos tipos de XSS:
$variable = sanitizeString($_POST[''user_input'']);
$variable = sanitizeMySQL($_POST[''user_input'']);
print("<body background=''http://localhost/image.php?".$variable."'' >");
Y si:
$_POST[''user_input'']="'' onload=alert(/xss/)";
parcheado
$variable=htmlspecialchars($variable,ENT_QUOTES);
print("<body background=''http://localhost/image.php?".$variable."'' >");
htmlspeicalchars está codificando comillas simples y dobles, asegúrese de que la variable que está imprimiendo también esté entre comillas, esto hace que sea imposible "romper" y ejecutar código.
Me pregunto sobre el concepto de sanitización. Le está diciendo a Mysql que haga exactamente lo que quiere que haga: ejecutar una declaración de consulta creada en parte por el usuario del sitio web. Ya estás construyendo la oración de forma dinámica utilizando la entrada del usuario, concatenando cadenas con datos proporcionados por el usuario. Obtienes lo que pides.
De todos modos, aquí hay algunos métodos más de desinfección ...
1) Para valores numéricos, siempre envíe manualmente al menos en algún lugar antes o mientras construye la cadena de consulta: "SELECCIONAR campo1 FROM tblTest WHERE (id =". (Int) $ val. ")";
2) Para las fechas, primero convierta la variable a la marca de tiempo de Unix. Luego, use la función Mysql FROM_UNIXTIME () para convertirla a una fecha. "SELECCIONAR field1 FROM tblTest WHERE (date_field> = FROM_UNIXTIME (". Strtotime ($ val). ")";. Esto en realidad se necesita algunas veces para tratar cómo Mysql interpreta y almacena fechas diferentes de las secuencias de comandos o del sistema operativo.
3) Para cadenas cortas y predecibles que deben seguir cierto estándar (nombre de usuario, correo electrónico, número de teléfono, etc.), usted puede a) hacer declaraciones preparadas; o b) regex u otra validación de datos.
4) Para cadenas que no seguirían ningún estándar real y que pueden o no tener código preoperado o doblemente escapado y ejecutable por todos lados (texto, memos, marcado wiki, enlaces, etc.), puedes a) hacer declaraciones preparadas; o b) almacenar ay convertir de forma binaria / blob - convirtiendo cada carácter a representación binaria, hexadecimal o decimal antes de pasar el valor a la cadena de consulta y convertir al extraer. De esta forma, puede centrarse más en la validación html solo cuando escupir el valor almacenado de nuevo.