tipos - sqli php
¿Cómo permitir consultas SELECT y prevenir otras? (6)
En nuestra aplicación, los usuarios pueden crear funciones de exportación personalizadas en forma de declaraciones SQL. Algo como esto:
SELECT name, age, date_birth FROM users WHERE group_id = 2
No quiero que borren toda la base de datos insertando una declaración DELETE. Mis ideas serían:
- Use una cuenta de SQL, que solo está permitida a SELECT. (No quiero hacer esto, si hay alternativas).
- Use una expresión regular mágica que verifique si la consulta es peligrosa o no. (¿Sería esto bueno? ¿Ya existe una expresión regular?)
Estamos utilizando PHP DOP.
Como yo lo veo, hay tres opciones para elegir:
Opción 1
Cree una herramienta que creará la consulta para el usuario en el fondo. Simplemente haciendo clic en los botones e introduciendo los nombres de las tablas. De esta manera, puede detectar todos los comportamientos extraños en segundo plano, lo que lo pone fuera de peligro por consultas que no desea que se ejecuten.
opcion 2
Cree un usuario de MySQL al que solo se le permita hacer consultas SELECT
. Creo que incluso puedes decidir en qué tablas se puede seleccionar ese usuario. Utilice ese usuario para ejecutar las consultas que ingrese el usuario. Cree un usuario separado que tenga los permisos que desea para hacer sus consultas de UPDATE
, INSERT
y DELETE
.
Opcion 3
Antes de ejecutar la consulta, asegúrese de que no haya nada dañino en ella. Escanear la consulta por mala sintaxis.
Ejemplo:
// Check if SELECT is in the query
if (preg_match(''/SELECT/'', strtoupper($query)) != 0) {
// Array with forbidden query parts
$disAllow = array(
''INSERT'',
''UPDATE'',
''DELETE'',
''RENAME'',
''DROP'',
''CREATE'',
''TRUNCATE'',
''ALTER'',
''COMMIT'',
''ROLLBACK'',
''MERGE'',
''CALL'',
''EXPLAIN'',
''LOCK'',
''GRANT'',
''REVOKE'',
''SAVEPOINT'',
''TRANSACTION'',
''SET'',
);
// Convert array to pipe-seperated string
// strings are appended and prepended with /b
$disAllow = implode(''|'',
array_map(function ($value) {
return ''/b'' . $value . ''/b'';
}
), $disAllow);
// Check if no other harmfull statements exist
if (preg_match(''/(''.$disAllow.'')/gai'', $query) == 0) {
// Execute query
}
}
Nota: Podría agregar algún código PHP para filtrar los comentarios antes de realizar esta comprobación
Conclusión
Lo que está buscando hacer es bastante posible, sin embargo, nunca tendrá una garantía del 100 por ciento de que sea seguro. En lugar de permitir que los usuarios realicen las consultas, es mejor utilizar una API para proporcionar datos a los usuarios.
Existe otro método, si está utilizando la API de C, el método mysql_stmt_prepare () le permitirá consultar la field_count, que no será cero en una declaración de selección.
También le permite utilizar la preparación adecuada de SQL en su lugar.
No hagas esto, siempre habrá formas creativas de hacer una consulta peligrosa. Crea una API que construirá manualmente tus consultas.
Para mí, prefiero usar una cuenta MYSQL que solo permita SELECT.
Si desea una expresión regular, creo que todos los SQL SELECT se inician con "seleccionar", ¿algún otro? Estos son mis códigos:
$regex = "/^select/i";
if(preg_match($regex,$sql)){
//do your sql
}
Puede verificar si hay alguna declaración DELETE en la consulta mediante el siguiente código.
if (preg_match(''/(DELETE|DROP|TRUNCATE)/'',strtoupper($query)) == 0){
/*** Run your query here ***/
}
else {
/*** Do something ***/
}
Tenga en cuenta que, como señala Peter, es mejor tener un usuario de MySql separado.
Ya que dijo que preferiría no usar cuentas de solo lectura SQL si hay alternativas. Si está ejecutando PHP 5.5.21+ o 5.6.5+: sugeriría verificar si la primera declaración de la consulta es una instrucción SELECT y deshabilitar varias consultas en su conexión PDO.
Primero deshabilite las declaraciones múltiples en su objeto DOP ...
$pdo = new PDO(''mysql:host=hostname;dbname=database'', ''user'', ''password'', [PDO::MYSQL_ATTR_MULTI_STATEMENTS => false]);
Luego verifique que la primera declaración en la consulta use SELECT y que no haya subconsultas. El primer regex ignora los espacios en blanco iniciales, que son opcionales, y el segundo detecta el paréntesis que se usaría para crear subconsultas; esto tiene el efecto secundario de evitar que los usuarios usen funciones SQL, pero según su ejemplo, no creo que sea un problema.
if (preg_match(''/^(/s+)?SELECT/i'', $query) && preg_match(''/[()]+/'', $query) === 0) {
// run query
}
Si está ejecutando una versión anterior, puede deshabilitar las preparaciones emuladas para evitar que se ejecuten varias sentencias, pero esto se basa en el uso de PDO :: prepare ().
FWIW: Sería mucho mejor usar declaraciones preparadas / generar consultas seguras para sus usuarios o usar una cuenta de SQL de solo lectura. Si está usando MySQL y tiene derechos de administrador / acceso remoto, sugeriría usar la edición comunitaria de SQLyog ( https://github.com/webyog/sqlyog-community/wiki/Downloads ) para crear cuentas de usuario de solo lectura . Es extremadamente fácil de usar para que no tenga que aprender la sintaxis de GRANT.