¿Cuáles son las mejores funciones de desinfección de entrada PHP?

161

Estoy tratando de encontrar una función por la que pueda pasar todas mis cadenas para desinfectar. Para que la cadena que sale de ella sea segura para la inserción de la base de datos. Pero hay tantas funciones de filtrado por ahí que no estoy seguro de cuáles debo usar / necesitar.

Por favor, ayúdame a completar los espacios en blanco:

function filterThis($string) {
    $string = mysql_real_escape_string($string);
    $string = htmlentities($string);
    etc...
    return $string;
}
Lauren
fuente
44
para la inserción, está bien simplemente desinfectar contra la inyección SQL usando mysql_real_escape_string. Es cuando está utilizando los datos SELECCIONADOS (en la salida html o en una fórmula / función php) que debe aplicar htmlentities
davidosomething
Consulte stackoverflow.com/questions/60174/… para obtener una respuesta específica a la limpieza para la inserción de la base de datos (da un ejemplo de PDO, que otros han mencionado a continuación).
Pat

Respuestas:

433

¡Detener!

Estás cometiendo un error aquí. Oh, no, ha elegido las funciones PHP correctas para que sus datos sean un poco más seguros. Esta bien. Su error está en el orden de las operaciones. , y cómo y dónde usar estas funciones.

Es importante comprender la diferencia entre desinfectar y validar datos de usuario, escapar de datos para almacenamiento y escapar de datos para presentación.

Desinfección y validación de datos de usuario

Cuando los usuarios envían datos, debe asegurarse de que hayan proporcionado algo que usted espera.

Desinfección y filtrado

Por ejemplo, si espera un número, asegúrese de que los datos enviados sean un número . También puedes enviar datos de usuario a otros tipos. Todo lo que se envía se trata inicialmente como una cadena, por lo que obligar a los datos numéricos conocidos a ser un número entero o flotante hace que la desinfección sea rápida e indolora.

¿Qué pasa con los campos de texto de forma libre y las áreas de texto? Debe asegurarse de que no haya nada inesperado en esos campos. Principalmente, debe asegurarse de que los campos que no deben tener contenido HTML no contengan HTML. Hay dos formas de lidiar con este problema.

Primero, puede intentar escapar de la entrada HTML con htmlspecialchars. No debe usar htmlentitiespara neutralizar HTML, ya que también realizará la codificación de caracteres acentuados y otros que cree que también deben codificarse.

En segundo lugar, puede intentar eliminar cualquier posible HTML. strip_tagsEs rápido y fácil, pero también descuidado. HTML Purifier hace un trabajo mucho más completo al eliminar todo el HTML y también permite una lista blanca selectiva de etiquetas y atributos.

Las versiones modernas de PHP se entregan con la extensión de filtro , que proporciona una forma integral de desinfectar la entrada del usuario.

Validación

Asegurarse de que los datos enviados estén libres de contenido inesperado es solo la mitad del trabajo. También debe intentar asegurarse de que los datos enviados contengan valores con los que realmente pueda trabajar.

Si espera un número entre 1 y 10, debe verificar ese valor. Si está utilizando una de esas nuevas entradas numéricas elegantes de la era HTML5 con un control giratorio y pasos, asegúrese de que los datos enviados estén en línea con el paso.

Si esos datos provienen de lo que debería ser un menú desplegable, asegúrese de que el valor enviado sea uno que apareció en el menú.

¿Qué pasa con las entradas de texto que satisfacen otras necesidades? Por ejemplo, las entradas de fecha deben validarse a través de strtotimela clase DateTime . La fecha dada debe estar entre los rangos que espera. ¿Qué pasa con las direcciones de correo electrónico? La extensión de filtro mencionada anteriormente puede verificar que una dirección esté bien formada, aunque soy fanático de la biblioteca is_email .

Lo mismo es cierto para todos los demás controles de formulario. ¿Tienes botones de radio? Validar contra la lista. ¿Tienes casillas de verificación? Validar contra la lista. ¿Tienes un archivo cargado? Asegúrese de que el archivo sea del tipo esperado y trate el nombre del archivo como datos de usuario sin filtrar.

Cada navegador moderno viene con un conjunto completo de herramientas de desarrollo integradas, lo que hace que sea trivial para cualquiera manipular su formulario. ¡Su código debe suponer que el usuario ha eliminado por completo todas las restricciones del lado del cliente en el contenido del formulario !

Datos de escape para almacenamiento

Ahora que se ha asegurado de que sus datos están en el formato esperado y contienen solo los valores esperados, debe preocuparse por mantener esos datos en el almacenamiento.

Cada mecanismo de almacenamiento de datos tiene una forma específica de asegurarse de que los datos se escapen y codifiquen correctamente. Si está creando SQL, la forma aceptada de pasar datos en consultas es mediante declaraciones preparadas con marcadores de posición .

Una de las mejores formas de trabajar con la mayoría de las bases de datos SQL en PHP es la extensión PDO . Sigue el patrón común de preparar una declaración , vincular variables a la declaración y luego enviar la declaración y las variables al servidor . Si no ha trabajado con PDO antes, aquí hay un tutorial bastante bueno orientado a MySQL .

Algunas bases de datos SQL tienen sus propias extensiones especiales en PHP, incluidos SQL Server , PostgreSQL y SQLite 3 . Cada una de esas extensiones cuenta con soporte para sentencias preparadas que opera de la misma manera preparar-vincular-ejecutar que PDO. A veces es posible que necesite usar estas extensiones en lugar de PDO para admitir características o comportamientos no estándar.

MySQL también tiene sus propias extensiones PHP. Dos de ellos, de hecho. Solo quieres usar el que se llama mysqli . La antigua extensión "mysql" ha quedado en desuso y no es segura ni sana de usar en la era moderna.

Personalmente no soy fanático de mysqli. La forma en que realiza el enlace variable en las declaraciones preparadas es inflexible y puede ser difícil de usar. En caso de duda, use PDO en su lugar.

Si no está utilizando una base de datos SQL para almacenar sus datos, consulte la documentación de la interfaz de la base de datos que está utilizando para determinar cómo pasar los datos de manera segura a través de ella.

Cuando sea posible, asegúrese de que su base de datos almacene sus datos en un formato apropiado. Almacenar números en campos numéricos. Almacenar fechas en campos de fecha. Almacene dinero en un campo decimal, no en un campo de coma flotante. Revise la documentación proporcionada por su base de datos sobre cómo almacenar correctamente diferentes tipos de datos.

Datos de escape para presentación

Cada vez que muestre datos a los usuarios, debe asegurarse de que los datos se escapen de forma segura, a menos que sepa que no se deben escapar.

Al emitir HTML, casi siempre debe pasar cualquier información que fue originalmente suministrada por el usuario htmlspecialchars. De hecho, la única vez que no debe hacer esto es cuando sabe que el usuario proporcionó HTML y sabe que ya se ha desinfectado mediante una lista blanca.

Algunas veces necesitas generar Javascript usando PHP. ¡Javascript no tiene las mismas reglas de escape que HTML! Una forma segura de proporcionar valores proporcionados por el usuario a Javascript a través de PHP es a través de json_encode.

Y más

Hay muchos más matices para la validación de datos.

Por ejemplo, la codificación del juego de caracteres puede ser una gran trampa . Su aplicación debe seguir las prácticas descritas en " UTF-8 hasta el final ". Hay ataques hipotéticos que pueden ocurrir cuando trata los datos de cadena como el conjunto de caracteres incorrecto.

Anteriormente mencioné las herramientas de depuración del navegador. Estas herramientas también se pueden utilizar para manipular datos de cookies. Las cookies deben tratarse como entradas de usuario no confiables .

La validación y el escape de datos son solo un aspecto de la seguridad de las aplicaciones web. Debe conocer las metodologías de ataque de las aplicaciones web para poder construir defensas contra ellas.

Charles
fuente
Y al especificarlo, asegúrese de que esté en la lista de codificaciones compatibles.
Charles
3
Y no use htmlentities en absoluto, reemplácelo con htmlspecialchars con el fin de reemplazar solo <>, no todos los personajes de su entidad
su sentido común el
66
Solo asegúrese de no llamar htmlspecialcharsdos veces, porque habla de ello en la parte "Cuando los usuarios envían datos" y en la parte "Cuando se muestran los datos".
Savageman
2
Votado La respuesta más útil que he leído de muchas preguntas y respuestas sobre la inyección SQL.
akinuri
Absolutamente una respuesta de calidad con muchas explicaciones y enlaces para futuros usuarios para explorar más opciones. También
James Walker
32

La desinfección más efectiva para evitar la inyección de SQL es la parametrización mediante PDO. Mediante consultas parametrizadas, la consulta se separa de los datos, de modo que elimina la amenaza de la inyección SQL de primer orden.

En términos de eliminar HTML, strip_tagses probablemente la mejor idea para eliminar HTML, ya que simplemente eliminará todo. htmlentitieshace lo que parece, así que también funciona. Si necesita analizar qué HTML permitir (es decir, si desea permitir algunas etiquetas), debe usar un analizador existente maduro como HTML Purifier

Derek H
fuente
2
Aw hombre, escribí ese muro gigante de texto solo porque no vi a nadie mencionar HTML Purifier, y aquí me ganaste por unos 40 minutos. ;)
Charles
3
¿No deberías tirar solo HTML en la salida? En mi opinión, nunca debe cambiar los datos de entrada; nunca se sabe cuándo los necesitará
Joe Phillips
11

Entrada de base de datos: cómo evitar la inyección de SQL

  1. Verifique para asegurarse de que los datos de tipo entero, por ejemplo, sean válidos asegurándose de que realmente sea un entero
    • En el caso de las no cadenas, debe asegurarse de que los datos sean del tipo correcto
    • En el caso de las cadenas, debe asegurarse de que la cadena esté entre comillas en la consulta (obviamente, de lo contrario, ni siquiera funcionaría)
  2. Ingrese el valor en la base de datos mientras evita la inyección SQL (mysql_real_escape_string o consultas parametrizadas)
  3. Al recuperar el valor de la base de datos, asegúrese de evitar los ataques de Cross Site Scripting asegurándose de que no se pueda inyectar HTML en la página (htmlspecialchars)

Debe escapar de la entrada del usuario antes de insertarla o actualizarla en la base de datos. Aquí hay una forma más antigua de hacerlo. Desea utilizar consultas parametrizadas ahora (probablemente de la clase PDO).

$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);

Salida de la base de datos - Cómo prevenir XSS (Cross Site Scripting)

Úselo htmlspecialchars()solo cuando envíe datos desde la base de datos. Lo mismo se aplica para HTML Purifier. Ejemplo:

$html['username'] = htmlspecialchars($clean['username'])

Y finalmente ... lo que pediste

Debo señalar que si usa objetos PDO con consultas parametrizadas (la forma correcta de hacerlo), entonces no hay una manera fácil de lograrlo fácilmente. Pero si usa la antigua forma 'mysql', entonces esto es lo que necesitaría.

function filterThis($string) {
    return mysql_real_escape_string($string);
}
Joe Phillips
fuente
5

Mis 5 centavos

Aquí nadie entiende cómo mysql_real_escape_stringfunciona. Esta función no filtra ni "desinfecta" nada.
Por lo tanto, no puede usar esta función como un filtro universal que lo salvará de la inyección.
Puede usarlo solo cuando comprenda cómo funciona y dónde corresponda.

Tengo la respuesta a la pregunta muy similar que ya escribí: en PHP, al enviar cadenas a la base de datos, ¿debo ocuparme de los caracteres ilegales que usan htmlspecialchars () o usar una expresión regular?
Haga clic para obtener la explicación completa de la seguridad del lado de la base de datos.

En cuanto a las complicaciones, Charles tiene razón al decirle que separe estas funciones.
Solo imagine que va a insertar datos generados por el administrador, a quien se le permite publicar HTML. tu función lo estropeará.

Aunque aconsejaría contra htmlentities. Esta función quedó obsoleta hace mucho tiempo. Si desea sustituir únicamente <, >y "personajes en aras de la seguridad de HTML - utilizan la función que se desarrolló intencionalmente para tal fin - un htmlspecialchars () uno.

Su sentido común
fuente
1
mysql_real_escape_stringescapa caracteres necesarios dentro de una cadena. No es estrictamente filtrar o desinfectar, pero encerrar una cadena entre comillas tampoco lo es (y todo el mundo lo hace, casi nunca vi una pregunta al respecto). Entonces, ¿nada se desinfecta cuando escribimos SQL? Por supuesto no. Lo que impide la inyección de SQL es el uso de mysql_real_escape_string. También las citas adjuntas, pero todos lo hacen, y si prueba lo que hace, termina con un error de sintaxis SQL con esta omisión. La parte realmente peligrosa se maneja con mysql_real_escape_string.
Savageman
@Savageman lo siento amigo, no entiendes nada. No comprende la forma en que funciona mysql_real_escape_string. Estos "caracteres necesarios" SON citas. Ni esta función ni las citas solo desinfectan nada. Estas 2 cosas solo funcionan juntas . Hacer que la cadena de consulta sea sintácticamente correcta, no "segura de la inyección". ¿Y qué error de sintaxis obtendría solo WHERE id = 1? ;)
Su sentido común
Intente WHERE my_field = two words(sin comillas) para obtener el error de sintaxis. Su ejemplo es malo porque no necesita comillas ni escapes, solo una verificación numérica. Tampoco dije que las citas fueran inútiles. Dije que todos los usan, así que esta no es la fuente de problemas con respecto a la inyección SQL.
Savageman
1
@Savageman entonces, eso dije: solo puedes usarlo cuando entiendes cómo funciona y dónde corresponde. Acaba de admitir que mysql_real_escape_string no es aplicable en todas partes. En cuanto a everyone use themusted, puede consultar los códigos aquí en SO. Muchas personas no usan comillas con números. Imagínate. Por favor, tenga en cuenta que no estoy discutiendo aquí lo que ha dicho y lo que no. Solo estoy explicando las reglas básicas de seguridad de la base de datos. Será mejor que aprendas en lugar de discutir vacío. Nadie mencionó citas o casting aquí, pero m_r_e_s solo como si fuera magia. De lo que estoy hablando
su sentido común
1
uno arriba, así como @Charles. Como novato, la interacción de la base de datos ... hacer que las cosas sean seguras para la entrada y la visualización, caracteres especiales, problemas de inyección, ha sido una curva de aprendizaje muy empinada. Leer su publicación y la suya (así como sus otras respuestas de PHP a otras preguntas, me ha ayudado enormemente. Gracias por todo su aporte.
James Walker
2

Para la inserción de la base de datos, todo lo que necesita es mysql_real_escape_string(o usar consultas parametrizadas). Por lo general, no desea alterar los datos antes de guardarlos, que es lo que sucedería si los usara htmlentities. Eso conduciría a un desastre confuso más adelante cuando lo htmlentitiesvolviera a ejecutar para mostrarlo en algún lugar de una página web.

Utilizar htmlentities cuando muestre los datos en una página web en algún lugar.

Algo relacionado, si está enviando datos enviados a algún lugar en un correo electrónico, como con un formulario de contacto, por ejemplo, asegúrese de quitar las nuevas líneas de cualquier información que se utilizará en el encabezado (como De: nombre y dirección de correo electrónico, subect, etc. )

$input = preg_replace('/\s+/', ' ', $input);

Si no hace esto, es solo cuestión de tiempo antes de que los robots de spam encuentren su formulario y lo abusen, lo he aprendido por las malas.

Robar
fuente
2

Depende del tipo de datos que esté utilizando. El mejor general para usar seríamysqli_real_escape_string , pero, por ejemplo, sabes que no habrá contenido HTML, usar strip_tags agregará seguridad adicional.

También puede eliminar caracteres que sabe que no deberían permitirse.

Aaron Harun
fuente
1

Siempre recomiendo usar un pequeño paquete de validación como GUMP: https://github.com/Wixel/GUMP

Construya todas sus funciones básicas alrededor de una biblioteca como esta y es casi imposible olvidar el saneamiento. "mysql_real_escape_string" no es la mejor alternativa para un buen filtrado (como explica "Su sentido común"), y si olvida usarlo solo una vez, todo su sistema será atacable mediante inyecciones y otros asaltos desagradables.

Simon Schneider
fuente
1

Para todos los que están hablando y confiando en mysql_real_escape_string, deben notar que esa función fue desaprobada en PHP5 y ya no existe en PHP7.

En mi humilde opinión, la mejor manera de realizar esta tarea es utilizar consultas parametrizadas mediante el uso de PDO para interactuar con la base de datos. Verifique esto: https://phpdelusions.net/pdo_examples/select

Siempre use filtros para procesar la entrada del usuario. Ver http://php.net/manual/es/function.filter-input.php

Kuntur
fuente
Esto en realidad no responde la pregunta. Considere modificar su respuesta para incluir una solución.
kris
¡Espero que te guste!
Kuntur
Hago. ¡Buena respuesta!
kris
Sugiero tomar nota de que en PHP 7 mysqli_real_escape_string()está disponible.
Chris
Hola Chris, las soluciones expuestas aquí hacen referencia a mysql_real_escape_string, noté quién leyó a partir de ahora que ya no existe en PHP7 y propuse una alternativa usando PDO (y filtros) no mysqli. Siéntase libre de agregar una nota explicando una solución usando lo que sugiere. Saludos
Kuntur
0

Utiliza mysql_real_escape_string () en un código similar al siguiente.

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
  mysql_real_escape_string($user),
  mysql_real_escape_string($password)
);

Como dice la documentación, su propósito es escapar de caracteres especiales en la cadena pasada como argumento, teniendo en cuenta el conjunto de caracteres actual de la conexión para que sea seguro colocarlo en un mysql_query () . La documentación también agrega:

Si se van a insertar datos binarios, se debe usar esta función.

htmlentities () se usa para convertir algunos caracteres en entidades, cuando genera una cadena en contenido HTML.

kiamlaluno
fuente
0

Esta es una de las formas en que estoy practicando actualmente,

  1. Implante csrf y token de tentador de sal junto con la solicitud que debe realizar el usuario, y valídelos todos juntos desde la solicitud. Consulte aquí
  2. asegúrese de no confiar demasiado en las cookies del lado del cliente y asegúrese de practicar el uso de sesiones del lado del servidor
  3. cuando analice datos, asegúrese de aceptar solo el tipo de datos y el método de transferencia (como POST y GET)
  4. Asegúrese de usar SSL para su aplicación web / aplicación
  5. Asegúrese de generar también una solicitud de sesión de base de tiempo para restringir la solicitud de spam intencionalmente.
  6. Cuando los datos se analizan en el servidor, asegúrese de validar que la solicitud debe realizarse en el método de datos que desea, como json, html, etc., y luego continúe
  7. escapar de todos los atributos ilegales de la entrada utilizando el tipo de escape ... como la cadena de paisajes reales.
  8. después de eso, verifique solo el formato limpio del tipo de datos que desea del usuario.
    Ejemplo:
    - Correo electrónico: verifique si la entrada está en formato de correo electrónico válido
    - texto / cadena: Verifique que solo la entrada sea solo formato de texto (cadena)
    - número: verifique que solo se permita el formato de número.
    - etc. Pelase se refiere a la biblioteca de validación de entrada de php desde el portal de php
    - Una vez validado, continúe usando la declaración SQL preparada / PDO.
    - Una vez hecho esto, asegúrese de salir y terminar la conexión.
    - No olvide borrar el valor de salida una vez hecho.

Eso es todo lo que creo que es suficiente para el segundo básico. Debería evitar todo ataque importante del hacker.

Para la seguridad del lado del servidor, es posible que desee configurar su apache / htaccess para limitar los accesos y la prevención del robot y también la prevención del enrutamiento. Hay muchas cosas que hacer para la seguridad del lado del servidor además del segundo del sistema en el lado del servidor.

Puede aprender y obtener una copia del segundo desde el nivel htaccess apache sec (prácticas comunes)

Ahmad Anuar
fuente
0
function sanitize($string,$dbmin,$dbmax){
$string = preg_replace('#[^a-z0-9]#i', '', $string); //useful for strict cleanse, alphanumeric here
$string = mysqli_real_escape_string($con, $string); //get ready for db
if(strlen($string) > $dbmax || strlen($string) < $dbmin){
    echo "reject_this"; exit();
    }
return $string;
}
stkmedia
fuente
0

que hay de esto

$string = htmlspecialchars(strip_tags($_POST['example']));

o esto

$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');
jerryurenaa
fuente