¿Esta función simple agrega algo a las declaraciones preparadas?

0

He estado investigando cómo prevenir completamente contra la inyección de SQL, pero hay tantas formas diferentes de inyectar que me parece imposible prevenirlas por completo. Estoy utilizando declaraciones preparadas y presente la siguiente función simple para prevenir contra inyecciones de SQL. ¿Esto es seguro contra (la mayoría) de las inyecciones de SQL, si ejecuto esta función en cada variable publicada? También he leído sobre caracteres de varios bytes, ¿cómo puedo asegurar mis consultas contra eso?

function securevar($var)
{
    $var = str_replace("'", "'", $var); //secure '
    $var = str_replace('"', """, $var); //secure "
    return $var;
}
    
pregunta P.Yntema 26.10.2014 - 21:17
fuente

3 respuestas

7

No, no es así, use declaraciones preparadas como está más una sola consulta Funciones y correcta validación de entrada. El último es el predeterminado para la mayoría de las funciones en PHP (por ejemplo, mysqli::query Vs. mysqli::multi_query ).

Declaraciones preparadas

Las declaraciones preparadas enviarán los datos de una variable y su tipo por separado a su DBMS, que a su vez escapará a todos los caracteres ofensivos en su nombre o analizará los datos independientemente de la consulta real (según el DBMS). No hay nada que saber sobre qué personajes deben ser escapados y cuáles no. Esta es la forma más segura de lograrlo.

<?php

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new \mysqli(null, null, null, "database");
$mysqli->prepare("SELECT * FROM 'users' WHERE 'id' = ?");
$mysqli->bind_param("d", $_GET["id"]);
$mysqli->execute();
// ...

Toda esta complejidad se puede abstraer, eche un vistazo, por ejemplo, a Código fuente de Drupal.

Funciones de consulta únicas

Las funciones de consulta única aseguran que una consulta tuya siempre solo producirá una consulta única que se pasará al DBMS. Eliminando efectivamente cualquier posibilidad de que alguien termine su consulta y ejecute otra; un escenario típico con inyección SQL, ejemplo:

<?php

$_GET["id"] = "1;SET foreign_key_checks=0;DROP TABLE users";

$mysqli->multi_query("SELECT * FROM 'users' WHERE 'id' = {$_GET["id"]}");

Validación

Este es quizás el consejo más importante y siempre es importante, no importa lo que intentes lograr. Use las filter_* funciones integradas de PHP y verifique otros proyectos grandes para validar cosas que no están cubiertas por estas funciones.

Ejemplo combinado

Vamos a ponerlo todo junto.

<?php

// max_range default is PHP_INT_MAX.
$userId = filter_input(INPUT_GET, "id", FILTER_VALIDATE_INT, array(
  "options" => array("min_range" => 1),
));

// Contains either a valid integer now or either FALSE or NULL.
if ($userId === null || $userId === false) {
//if (!$userId) {
  throw new \InvalidArgumentException();
}

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new \mysqli(null, null, null, "database");
$stmt = $mysqli->prepare("SELECT 'name' FROM 'users' WHERE 'id' = ?");
%stmt->bind_param("d", $userId);
$stmt->execute();
$stmt->fetch($userName);
$stmt->close();
$mysqli->close();

exit("Hello {$userName} with {$userId}.");
    
respondido por el Fleshgrinder 26.10.2014 - 21:57
fuente
14

No. La inyección de SQL debe evitarse mediante la parametrización de sus consultas.

OWASP tiene algunos recursos excelentes para ayudarte con esto.

Aquí es una hoja de este tipo para mostrar esto en varios idiomas. La hoja de trucos de PHP también tiene más información sobre la inyección de SQL.

Para dirigirse directamente a su función de filtro codificado, consulte esta fuente demostrando la explotación de filtros codificados, incluidas las comillas y las comillas simples.

    
respondido por el KDEx 26.10.2014 - 21:28
fuente
1

Como dijeron @Douglas y @fleshgrinder antes, no.

Considere la siguiente solicitud:

SELECT title, news FROM news_table WHERE id = $id

Solicitado $id = 5 está bien, ahora si $id = 5 OR 1=1 mostrará todas las noticias ... No es un gran problema?

Ahora, si $id = 5 UNION SELECT login as title, password as news from secret_credentials_table where is_admin = 1 también debería ser una solicitud de SQL válida, sin comillas ...

  • Use las solicitudes preparadas
  • Los argumentos escritos también ayudan (¡pero tampoco es la bala de plata!)

Para el argumento escrito, si se asegura de que su $id es un número entero, entonces tal inyección es imposible. Pero, por supuesto, algunos solicitan la cadena de espera como entrada, por lo que pierde todos los beneficios de esto.

    
respondido por el Aif 27.10.2014 - 09:19
fuente

Lea otras preguntas en las etiquetas