sirve real_escape_string que para mysqli_real_escape_string mysqli_escape_string mysql_real_escape_string expects exactly alternative php mysql security

php - que - ¿Son mysql_real_escape_string() y mysql_escape_string() suficientes para la seguridad de la aplicación?



mysqli_real_escape_string() expects exactly 2 parameters (5)

¡No!

Actualización importante: después de probar el posible código de explotación proporcionado por el Coronel Shrapnel y revisar las versiones de MySQL 5.0.22, 5.0.45, 5.0.77 y 5.1.48, parece que el conjunto de caracteres GBK y posiblemente otros combinados con una versión de MySQL más baja que 5.0.77 puede dejar vulnerable su código si solo usa SET NAMES lugar de usar las mysql_set_charset específicas mysql_set_charset / mysqli_set_charset . Debido a que solo se agregaron en PHP 5.2.x, la combinación de PHP antiguo y MySQL antiguo puede generar una potencial vulnerabilidad de inyección SQL , incluso si usted pensó que estaba seguro y lo hizo todo correctamente, según el libro.

Sin configurar el juego de caracteres en combinación con mysql_real_escape_string , es posible que te sientas vulnerable a un exploit de juego de caracteres específico posible con versiones anteriores de MySQL. Más información sobre investigaciones anteriores .

Si es posible, usa mysql_set_charset . SET NAMES ... no es suficiente para protegerse contra este exploit específico si está utilizando una versión afectada de MySQL (anterior a 5.0.22 5.0.77).

¿Será suficiente mysql_real_rescape_string () para protegerme de los piratas informáticos y los ataques SQL? Preguntar porque escuché que estos no ayudan contra todos los vectores de ataque. Buscando el consejo de expertos.

EDITAR: Además, ¿qué pasa con los ataques SQL LIKE?


@Charles es extremadamente correcto!

Te arriesgas por varios tipos de ataques conocidos de SQL, incluidos, como mencionaste

  • Inyección SQL: ¡sí! Mysql_Escape_String probablemente TODAVÍA lo mantiene susceptible a las inyecciones de SQL, dependiendo de dónde use las variables de PHP en sus consultas.

Considera esto:

$sql = "SELECT number FROM PhoneNumbers " . "WHERE " . mysql_real_escape_string($field) . " = " . mysql_real_escape_string($value);

¿Puede eso escaparse de forma segura y precisa de esa manera? ¡NO! ¿Por qué? porque un hacker aún podría hacer esto:

Repite después de mi:

mysql_real_escape_string() solo está destinado a escapar datos variables, NO nombres de tablas, columnas, y especialmente no campos LIMIT.

  • COMO exploits: LIKE "$ data%" donde $ data podría ser "%" que devolvería TODOS los registros ... lo que bien podría ser un ataque de seguridad ... solo imagine una búsqueda por los últimos cuatro dígitos de una tarjeta de crédito. ¡OOP! ¡Ahora los hackers pueden recibir cada número de tarjeta de crédito en su sistema! (Por cierto: ¡casi nunca se recomienda guardar tarjetas de crédito completas!)

  • Charset Exploits: No importa lo que digan los que odian, Internet Explorer sigue siendo , en 2011, vulnerable a los Exploits de Conjunto de Caracteres, y eso si has diseñado tu página HTML correctamente, con el equivalente de <meta name="charset" value="UTF-8"/> ! Estos ataques son MUY desagradables ya que le dan al pirata informático tanto control como las inyecciones directas de SQL: por ejemplo, lleno.

Aquí hay un código de ejemplo para demostrar todo esto:

// Contains class DBConfig; database information. require_once(''../.dbcreds''); $dblink = mysql_connect(DBConfig::$host, DBConfig::$user, DBConfig::$pass); mysql_select_db(DBConfig::$db); //print_r($argv); $sql = sprintf("SELECT url FROM GrabbedURLs WHERE %s LIKE ''%s%%'' LIMIT %s", mysql_real_escape_string($argv[1]), mysql_real_escape_string($argv[2]), mysql_real_escape_string($argv[3])); echo "SQL: $sql/n"; $qq = mysql_query($sql); while (($data = mysql_fetch_array($qq))) { print_r($data); }

Aquí están los resultados de este código cuando se pasan varias entradas:

$ php sql_exploits.php url http://www.reddit.com id SQL generated: SELECT url FROM GrabbedURLs WHERE url LIKE ''http://www.reddit.com%'' ORDER BY id; Returns: Just URLs beginning w/ "http://www.reddit.com" $ php sql_exploits.php url % id SQL generated: SELECT url FROM GrabbedURLs WHERE url LIKE ''%%'' ORDER BY id; Results: Returns every result Not what you programmed, ergo an exploit --

$ php sql_exploits.php 1 = 1 '' http://www.reddit.com '' id Resultados: Devuelve cada columna y cada resultado.

Luego están los EXITOS LÍMITES desagradablemente REALES:

$ php sql_exploits.php url > ''http://www.reddit.com'' > "UNION SELECT name FROM CachedDomains" Generated SQL: SELECT url FROM GrabbedURLs WHERE url LIKE ''http://reddit.com%'' LIMIT 1 UNION SELECT name FROM CachedDomains; Returns: An entirely unexpected, potentially (probably) unauthorized query from another, completely different table.

Si usted entiende el SQL en los ataques o no, es irrevelante. Lo que esto ha demostrado es que mysql_real_escape_string () es eludido fácilmente incluso por los hackers más inmaduros. Eso es porque es un mecanismo de defensa REACTIVO. Solo soluciona ataques muy limitados y CONOCIDOS en la Base de Datos.

Todos los escapes NUNCA serán suficientes para asegurar las bases de datos. De hecho, puede REACCIONAR explícitamente a cada exploit CONOCIDO y, en el futuro, su código probablemente se volverá vulnerable a los ataques descubiertos en el futuro.

La defensa adecuada, y única (realmente), es PROACTIVA: use declaraciones preparadas. Las declaraciones preparadas se diseñan con especial cuidado para que SOLO se ejecute SQL válido y PROGRAMADO. Esto significa que, cuando se realiza correctamente, las probabilidades de que SQL inesperado se pueda ejecutar se reducen drásticamente.

Teóricamente, las declaraciones preparadas que se implementan perfectamente serían inmunes a TODOS los ataques, conocidos y desconocidos, ya que son una técnica de SERVER SIDE, manejada por DATABASE SERVERS THEMSELVES y las bibliotecas que interactúan con el lenguaje de programación. Por lo tanto, SIEMPRE tiene la garantía de estar protegido contra CADA CASO CONOCIDO, al mínimo.

Y es menos código:

$pdo = new PDO($dsn); $column = ''url''; $value = ''http://www..com/''; $limit = 1; $validColumns = array(''url'', ''last_fetched''); // Make sure to validate whether $column is a valid search parameter. // Default to ''id'' if it''s an invalid column. if (!in_array($column, $validColumns) { $column = ''id''; } $statement = $pdo->prepare(''SELECT url FROM GrabbedURLs '' . ''WHERE '' . $column . ''=? '' . ''LIMIT '' . intval($limit)); $statement->execute(array($value)); while (($data = $statement->fetch())) { }

Ahora que no era tan difícil ¿verdad? Y es un cuarenta y siete por ciento menos de código (195 caracteres (PDO) frente a 375 caracteres (mysql_). Es lo que llamo, "lleno de victoria".

EDITAR: Para abordar toda la controversia que esta respuesta provocó, permítanme reiterar lo que ya he dicho:

El uso de declaraciones preparadas le permite a uno aprovechar las medidas de protección del servidor SQL, y por lo tanto está protegido contra cosas que las personas del servidor SQL conocen. Debido a este nivel adicional de protección, usted es mucho más seguro que usar escapes, sin importar cuán minucioso sea.


Debería considerar el uso de sentencias preparadas / consultas parametrizadas en su lugar. La idea es que le de a la base de datos una consulta con marcadores de posición. Luego le da a la base de datos sus datos y le dice qué marcador de posición reemplazar con dicha información, y la base de datos se asegura de que sea válida y no le permita sobrepasar el marcador de posición (es decir, no puede finalizar una consulta actual y luego agregar el suyo, un ataque común).


Sí. Si no te olvidas de:

  1. Escapar datos de cadena con mysql_real_rescape_string()
  2. Emitir números a números explícitamente (es decir: $id = (int)$_GET[''id'']; )

entonces estás protegido.


Yo personalmente prefiero las declaraciones preparadas :

<?php $stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?"); if ($stmt->execute(array($_GET[''name'']))) { while ($row = $stmt->fetch()) { print_r($row); } } ?>

Sería muy fácil pasar por alto una u otra variable específica que se ha perdido al utilizar una de las *escape_string() , pero si todas sus consultas son declaraciones preparadas, entonces están todas bien, y el uso de variables interpoladas se destacará como un pulgar dolorido

Pero esto no es suficiente para garantizar que no seas vulnerable a exploits remotos: si pasas un &admin=1 con solicitudes GET o POST para indicar que alguien es un administrador, cada uno de tus usuarios podría actualizar fácilmente sus privilegios. con dos o tres segundos de esfuerzo. Tenga en cuenta que este problema no siempre es tan obvio :), pero esta es una manera fácil de explicar las consecuencias de confiar demasiado en los datos proporcionados por el usuario.