[php] ¿Debo protegerme contra la inyección de SQL si utilicé un menú desplegable?


4 Answers

Sí, necesitas protegerte contra esto.

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

Si no limpia estos datos, su base de datos será destruida. (Esta podría no ser una declaración de SQL totalmente válida, pero espero haber aclarado mi punto).

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

Si trataste de restringir este comportamiento de uso adicional en tu página, mis opciones incluyen deshabilitar ese comportamiento, o simplemente escribir una solicitud HTTP personalizada en tu servidor que imite de todos modos el envío de este formulario. Hay una herramienta llamada curl usada exactamente para eso, y creo que el comando para enviar esta inyección de SQL se parecería a 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 de nuevo, espero haber llegado a un punto).

Entonces, voy a reiterar:

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

No asuma que cualquier entrada del usuario es segura. Es potencialmente inseguro, incluso si llega por algún medio que no sea un formulario. Nada de eso es lo suficientemente confiable para evitar protegerse de la inyección de SQL.

Question

Entiendo que NUNCA debe confiar en la información del usuario de 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 proviene de un menú desplegable (ver a continuación)?

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

No hay un área para la entrada del usuario tipeado para consultar las bases de datos, solo listas 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>



Todo 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 que alguien cree un bot para imitar al cliente o escribirlo desde un terminal si así lo desean. Nunca asuma que, debido a que programó el cliente, actuará como usted cree que sucederá. Esto es realmente fácil de burlar.

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




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




Las otras respuestas ya cubren lo que necesita saber. Pero quizás ayude aclarar algo más:

Hay DOS COSAS que debe 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 filtro confiable para usted.

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

La mayoría de los marcos y CMS tienen constructores de formularios que lo 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 las declaraciones de SQL ..

.. o deja que las declaraciones preparadas hagan el trabajo por ti.

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

En general, cualquier variable que inserte en una declaración MySQL debe ser una cadena, o algo que PHP puede convertirse de manera confiable en una cadena que MySQL puede digerir. Tales como, números.

Para las cadenas, debes elegir uno de los 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 usar declaraciones preparadas o constructores de consultas.
  • En MySQLi, puede usar declaraciones preparadas.
  • La mayoría de los marcos y CMS proporcionan constructores de consultas que lo ayudan con esta tarea.

Si está tratando con un número, puede omitir el escape y las comillas (esta es la razón por la cual las declaraciones preparadas permiten especificar un tipo).

Es importante señalar que se escapa de las variables para la declaración de SQL, y NO para la base de datos en sí . La base de datos almacenará la cadena original, pero la instrucción necesita una versión de escape.

¿Qué pasa si omites uno de estos?

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

Primero, puede llevar su aplicación 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 fallará.

En segundo lugar, puede haber todo tipo de otros ataques de inyección que debe tener en cuenta: 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 "bloquear la aplicación".

Pero, incluso si tiene un campo de texto libre donde permite cualquier entrada sin validación, aún podría guardar esto en la base de datos así si lo escapa adecuadamente cuando va a una declaración de base de datos. El problema surge cuando quieres usar esta cadena en alguna parte.

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

Si no escapa las variables para las sentencias de SQL , pero sí validó la entrada de formularios, entonces aún puede ver cosas malas sucediendo.

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

En segundo lugar, puede dar como resultado sentencias de SQL no válidas y, por lo tanto, bloquear su aplicación. Por ejemplo, si una variable contiene un carácter de comillas o comillas dobles, dependiendo de qué tipo de comillas utilice, obtendrá una declaración de MySQL no válida.

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

Si su entrada de usuario desde formularios ya está filtrada / validada, la inyección SQl intencional puede ser menos probable, SI su entrada se reduce a una lista de opciones codificadas, o si está restringida a números. Pero cualquier entrada de texto libre se puede usar para la inyección SQL, si no se escapan adecuadamente las variables en las sentencias SQL.

E incluso si no tiene ninguna entrada de formulario, todavía podría tener cadenas de todo tipo de fuentes: leer desde el sistema de archivos, raspado de Internet, etc. Nadie puede garantizar que estas cadenas sean seguras.




Sí.

Cualquiera puede suplantar cualquier cosa por los valores que realmente se envían -

POR LO TANTO, para validar los menús desplegables, puede verificar que el valor con el que está trabajando esté en el menú desplegable; algo como esto sería la mejor manera (más sensatamente paranoica):

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

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

} else {

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

}



Related