¿Tengo que protegerme de la inyección SQL si utilizo un menú desplegable?


Entiendo que NUNCA debe confiar en la entrada del usuario desde un formulario, principalmente debido a la posibilidad de inyección SQL.

Sin embargo, ¿esto también se aplica a un formulario donde la única entrada es de un menú desplegable(ver más abajo)?

Estoy guardando el $_POST['size'] en una sesión que luego se utiliza en todo el sitio para consultar las diversas bases de datos (con una consulta Select mysqli) y cualquier inyección SQL definitivamente dañaría (posiblemente las eliminaría).

No hay un área para la entrada de usuario escrita para consultar el bases de datos, solo desplegables.

<form action="welcome.php" method="post">
<select name="size">
  <option value="All">Select Size</option> 
  <option value="Large">Large</option>
  <option value="Medium">Medium</option>
  <option value="Small">Small</option>
</select>
<input type="submit">
</form>
Author: doppelgreener, 2014-03-20

11 answers

Usted podría hacer algo tan simple como el siguiente ejemplo para asegurarse de que el tamaño publicado es lo que espera.

$possibleOptions = array('All', 'Large', 'Medium', 'Small');

if(in_array($_POST['size'], $possibleOptions)) {
    // Expected
} else {
    // Not Expected
}

Entonces use mysqli_* si está utilizando una versión de php >= 5.3.0 que debería ser, para guardar su resultado. Si se usa correctamente, esto ayudará con la inyección sql.

 68
Author: Oliver Bayes-Shelton,
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
2014-03-20 13:27:53

Sí, necesita protegerse contra esto.

Déjame mostrarte por qué, usando la consola de desarrolladores de Firefox:

he editado uno de los valores en el menú desplegable para que sea una instrucción de tabla desplegable

Si no limpia estos datos, su base de datos será destruida. (Esto podría no ser una sentencia SQL totalmente válida, pero espero haber conseguido mi punto a través.)

Solo porque haya limitado las opciones disponibles en su menú desplegable no significa que haya limitado los datos que puedo enviar a su servidor.

Si usted intentó restrinja esto aún más usando el comportamiento en su página, mis opciones incluyen deshabilitar ese comportamiento, o simplemente escribir una solicitud HTTP personalizada a su servidor que imita este envío de formulario de todos modos. Hay una herramienta llamada rizo se usa exactamente para eso, y yo creo que el comando para enviar esta inyección SQL de todos modos se vería algo como esto:

curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--"  http://www.example.com/profile/save

(Esto podría no ser un comando curl totalmente válido, pero nuevamente, espero haber entendido mi punto al otro lado.)

Por lo tanto, voy a reiterar:

NUNCA confíe en la entrada del usuario. SIEMPRE protégete.

No asumas que ninguna entrada del usuario es segura. Es potencialmente inseguro incluso si llega a través de algún medio que no sea un formulario. Nada de esto es lo suficientemente confiable como para renunciar a protegerse de la inyección SQL.

 192
Author: doppelgreener,
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
2014-03-26 09:03:45

Como esta pregunta fue etiquetada con sql-injection , aquí hay una respuesta con respecto a este tipo particular de ataque:

Como se le ha dicho en los comentarios, debe usar declaraciones preparadas para cada consulta que involucre cualquier dato variable, sin excepciones.

Independientemente de cualquier cosa HTML!
Es esencial entender que las consultas SQL deben formatearse correctamente independientemente de de cualquier factor externo, ya sea HTML entrada o cualquier otra cosa.

Aunque puede usar la lista blanca sugerida en otras respuestas para el propósito de validación de entrada, no debería afectar a ninguna acción relacionada con SQL-tienen que seguir siendo las mismas, sin importar si validó la entrada HTML o no. Esto significa que aún tiene que usar sentencias preparadas al agregar cualquier variable a la consulta.

Aquí puede encontrar una explicación completa, por qué las declaraciones preparadas son una necesidad y cómo usarlas correctamente y dónde no lo son aplicable y qué hacer en tal caso: La Guía del autoestopista para la protección de inyección SQL

También, esta pregunta fue etiquetada con mysqli. En su mayoría por accidente, supongo, pero de todos modos, tengo que advertirle que raw mysqli no es una sustitución adecuada para las antiguas funciones mysq_* . Simplemente porque si se usa en el estilo antiguo, no agregará seguridad en absoluto. Si bien el apoyo a las declaraciones preparadas es doloroso y problemático, hasta el punto de que el usuario promedio de PHP es incapaz de esforzarse en absoluto. Por lo tanto, si ninguna opción es OR o algún tipo de biblioteca de abstracción, entonces PDO es su única opción.

 44
Author: Your Common Sense,
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 12:25:33

Sí.

Cualquiera puede falsificar cualquier cosa para los valores que realmente se envían {

Por lo tanto, para validar los menús desplegables, solo puede verificar para asegurarse de que el valor con el que está trabajando estaba en el menú desplegable, algo como esto sería la mejor manera(más paranoica):

if(in_array($_POST['ddMenu'], $dropDownValues){

    $valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];

} else {

    die("effin h4x0rs! Keep off my LAMP!!"); 

}
 12
Author: rm-vanda,
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
2014-11-22 03:09:57

Una forma de protegerse contra que los usuarios cambien sus menús desplegables usando la consola es usar solo valores enteros en ellos. Luego puede validar que el valor POST contenga un entero y usar una matriz para convertirlo en texto cuando sea necesario. Por ejemplo:

<?php
// No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful.
$sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);

echo '<select name="size">';
foreach($sizes as $i => $s) {
    echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>';
}
echo '</select>';

Entonces puede usar $size en su consulta con el conocimiento de que solo contendrá FALSE o un entero.

 8
Author: Styphon,
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
2014-03-20 14:01:12

Las otras respuestas ya cubren lo que necesita saber. Pero tal vez ayuda a aclarar un poco más:

Hay DOS COSAS que debes hacer:

1. Validar los datos del formulario.

Como la respuesta de Jonathan Hobbs muestra muy claramente, la elección del elemento html para la entrada del formulario no hace ningún filtrado confiable para usted.

La validación se realiza generalmente de una manera que no altera los datos, pero que muestra el formulario de nuevo, con los campos marcados como " Please corrija esto".

La mayoría de los frameworks y CMSes tienen constructores de formularios que te ayudan con esta tarea. Y no solo eso, también ayudan contra CSRF (o "XSRF"), que es otra forma de ataque.

2. Sanitize / Escape variables en sentencias SQL..

.. o deje que las declaraciones preparadas hagan el trabajo por usted.

Si construye una instrucción (Mi)SQL con cualquier variable, provista por el usuario o no, debe escapar y citar estas variables.

Generalmente, cualquier variable que inserte en una sentencia MySQL debe ser una cadena, o algo que PHP pueda convertir de forma fiable en una cadena que MySQL pueda digerir. Por ejemplo, números.

Para cadenas, debe elegir uno de varios métodos para escapar de la cadena, es decir, reemplazar cualquier carácter que tenga efectos secundarios en MySQL.

  • En MySQL + PHP de la vieja escuela, mysql_real_escape_string() hace el trabajo. El problema es que es demasiado fácil de olvidar, por lo que debe utilizar absolutamente preparado sentencias o creadores de consultas.
  • En MySQLi, puede usar declaraciones preparadas.
  • La mayoría de los frameworks y CMSes proporcionan constructores de consultas que le ayudan con esta tarea.

Si está tratando con un número, podría omitir el escape y las comillas (por eso las instrucciones preparadas permiten especificar un tipo).

Es importante señalar que se escapan las variables para la instrucción SQL, y NO para la propia base de datos. La base de datos almacenará la cadena original, pero la instrucción necesita una versión escapada.

¿Qué sucede si omites uno de estos?

Si no usa validación de formulario, pero desinfecta su entrada SQL, es posible que vea todo tipo de cosas malas sucediendo, ¡pero no verá inyección SQL! (*)

Primero, puede llevar su solicitud a un estado que no planeó. Por ejemplo, si desea calcular la edad promedio de todos los usuarios, pero un usuario dio "aljkdfaqer" para la edad, su cálculo será fallar.

En segundo lugar, puede haber todo tipo de otros ataques de inyección que debe considerar: Por ejemplo, la entrada del usuario podría contener javascript u otras cosas.

Todavía puede haber problemas con la base de datos: Por ejemplo, si un campo (columna de la tabla de la base de datos) está limitado a 255 caracteres, y la cadena es más larga que eso. O si el campo solo acepta números e intenta guardar una cadena no numérica en su lugar. Pero esto no es "inyección", es solo " estrellarse aplicación".

Pero, incluso si tiene un campo de texto libre donde permite cualquier entrada sin validación en absoluto, todavía podría guardar esto en la base de datos de la misma manera, si se escapa correctamente cuando va a una instrucción de base de datos. El problema viene cuando quieres usar esta cadena en algún lugar.

(*) o esto sería algo realmente exótico.

Si no escapa variables para sentencias SQL, pero validó la entrada del formulario, aún puede ver cosas malas suceder.

Primero, corre el riesgo de que cuando guarde datos en la base de datos y los cargue de nuevo, ya no serán los mismos datos, "perdidos en la traducción".

En segundo lugar, puede resultar en sentencias SQL no válidas y, por lo tanto, bloquear su aplicación. Por ejemplo, si alguna variable contiene un carácter de comilla o comilla doble, dependiendo del tipo de comilla que utilice, obtendrá una instrucción MySQL no válida.

En tercer lugar, todavía puede causar inyección SQL.

Si su entrada de usuario desde formularios ya está filtrado / validado, la inyección SQl intencional puede ser menos probable, SI su entrada se reduce a una lista codificada de opciones, o si está restringida a números. Pero cualquier entrada de texto libre se puede usar para la inyección SQL, si no escapa correctamente las variables en las instrucciones SQL.

E incluso si no tiene entrada de formulario en absoluto, todavía podría tener cadenas de todo tipo de fuentes: Leídas del sistema de archivos, raspadas de Internet, etc. Nadie puede garantizar que estos las cuerdas están a salvo.

 7
Author: donquixote,
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:54:25

Su navegador web no "sabe" que está recibiendo una página de php, todo lo que ve es html. Y la capa http sabe incluso menos que eso. Necesita ser capaz de manejar casi cualquier tipo de entrada que pueda cruzar la capa http (afortunadamente para la mayoría de las entradas php ya dará un error). Si usted está tratando de evitar malicioso solicitudes de echar a perder su db, entonces usted necesita para suponer que el hombre en el otro extremo sabe lo que está haciendo, y que él no está limitado a lo que se puede ver en su navegador en circunstancias normales(por no hablar de lo que se puede jugar con las herramientas de desarrollo de un navegador). Así que sí, necesita atender cualquier entrada de su menú desplegable, pero para la mayoría de las entradas puede dar un error.

 6
Author: Nameless One,
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
2014-03-20 15:33:02

El hecho de que haya restringido al usuario a usar solo valores de una determinada lista desplegable es irrelevante. Un usuario técnico puede capturar la solicitud http enviada a su servidor antes de que salga de su red, modificarla utilizando una herramienta como un servidor proxy local y luego continuarla en su camino. Usando la solicitud alterada, pueden enviar valores de parámetro que no son los que ha especificado en la lista desplegable. Los desarrolladores tienen que tener la mentalidad de que las restricciones del cliente son a menudo sin sentido, ya que cualquier cosa en un cliente puede ser alterada. La validación del servidor se requiere en cada punto en el que los datos del cliente ingresan. Los atacantes confían en la ingenuidad de los desarrolladores en este único aspecto.

 6
Author: Jason Higgins,
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
2014-03-20 19:19:17

Lo mejor es usar una consulta parametrizada para garantizar que no haya inyección SQL. En ese caso, el aspecto de la consulta sería el siguiente:

SELECT * FROM table WHERE size = ?

Cuando se proporciona una consulta como la anterior con texto que no se verifica para la integridad (la entrada no se valida en el servidor) y contiene código de inyección SQL, se manejará correctamente. En otras palabras, la solicitud resultará en que algo como esto suceda en la capa de base de datos:

SELECT * FROM table WHERE size = 'DROP table;'

Esto simplemente seleccionará 0 resultados como devuelve lo que hará que la consulta sea ineficaz para causar daño a la base de datos sin la necesidad de una lista blanca, una verificación u otras técnicas. Tenga en cuenta que un programador responsable hará la seguridad en capas, y a menudo validará además de parametrizar las consultas. Sin embargo, hay muy pocas razones para no parametrizar sus consultas desde una perspectiva de rendimiento y la seguridad añadida por esta práctica es una buena razón para familiarizarse con consultas parametrizadas.

 5
Author: Dan Smith,
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
2014-03-20 20:31:15

Lo que se envía desde su formulario llega a su servidor como texto a través de los cables. No hay nada que impida a nadie crear un bot para imitar al cliente o escribirlo desde una terminal si lo desean. Nunca asuma que porque programó al cliente actuará como usted piensa que lo hará. Esto es muy fácil de falsificar.

Ejemplo de lo que puede y sucederá cuando confíes en el cliente.

 4
Author: GenericJam,
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
2014-03-22 18:26:29

Un hacker puede omitir completamente el navegador, incluida la comprobación de formularios Javascript, enviando una solicitud utilizando Telnet. Por supuesto, él mirará el código de su página html para obtener los nombres de campo que tiene que usar, pero a partir de entonces es 'todo va' para él. Por lo tanto, debe verificar todos los valores enviados en el servidor como si no se originaran en su página html.

 4
Author: user1452686,
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
2014-03-25 22:45:10