La inyección SQL es una falla de seguridad en las aplicaciones web donde los atacantes insertan código SQL dañino a través de la entrada del usuario. Esto puede permitirles acceder al contenido de la base de datos de cambios de datos confidenciales o incluso tomar el control del sistema. Es importante conocer la inyección SQL para mantener seguras las aplicaciones web.
La inyección SQL (SQLi) es una vulnerabilidad de seguridad que ocurre cuando un atacante puede manipular las consultas de la base de datos de una aplicación web insertando código SQL malicioso en los campos de entrada del usuario. Estas consultas inyectadas pueden manipular la base de datos subyacente para recuperar, modificar o eliminar datos confidenciales. En algunos casos, los atacantes pueden incluso aumentar los privilegios y obtener control total sobre la base de datos o el servidor.

Ejemplo del mundo real:
En 2019, la filtración de datos de Capital One se produjo debido a una aplicación web mal configurada que permitió a un atacante explotar una vulnerabilidad de inyección SQL. Esto resultó en la filtración de datos personales de más de 100 millones de clientes, incluidos nombres, direcciones y puntajes crediticios.
Nivel de seguridad de inyección SQL
DVWA proporciona cuatro niveles de seguridad para inyección SQL para ayudar a los estudiantes a ver cómo las diferentes protecciones afectan los ataques:
1. Baja seguridad
La aplicación toma su entrada y la coloca directamente en la consulta SQL sin filtrado.
$id = $_GET['id'];$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';- Entrando
':Rompe la consulta y hace que la base de datos arroje un error que revela que es vulnerable. - Entrando
1' OR '1'='1:Engaña la consulta para que siempre sea verdadera para que se devuelvan todos los usuarios. - Entrando
1' UNION SELECT user password FROM users--:Se une a otra consulta para recuperar datos ocultos como nombres de usuario y contraseñas.
2. Seguridad media
La aplicación aplica desinfección de entrada básica utilizando funciones comoaddslashes()escapar'.
$id = addslashes($_GET['id']);$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';¿Cómo puede ser el ataque?
un sencillo'La inyección ya no funcionará (porque se vuelve').
Pero los atacantes aún pueden evitar el uso de la inyección numérica (ya que los números no necesitan comillas).
Ejemplo:
desinstalar cli angular
1 OR 1=1Esto todavía devuelve todos los registros.
3. Alta Seguridad
La aplicación utiliza declaraciones preparadas (consultas parametrizadas) para manejar de forma segura la entrada del usuario.
$stmt = $pdo->prepare('SELECT first_name last_name FROM users WHERE user_id = ?');$stmt->execute([$id]);Ataque:
Intentos como' OR 1=1oUNION SELECTya no funciona.
La consulta trata todas las entradas como datos, no como código SQL.
Tipos de inyección SQL
Existen diferentes tipos de inyección SQL
1. Inyección SQL basada en errores
La inyección SQL basada en errores es un tipo de inyección SQL dentro de banda en la que un atacante hace intencionadamente que la base de datos genere un mensaje de error. Luego, el atacante analiza este mensaje de error para obtener información valiosa sobre la estructura de la base de datos, como nombres de tablas y columnas, que puede usarse para diseñar ataques más precisos.
Cómo funciona
Este ataque se dirige a aplicaciones que revelan errores sin procesar de la base de datos en lugar de mostrar mensajes genéricos. Al inyectar entradas maliciosas que rompen la sintaxis SQL, los atacantes desencadenan estos errores y obtienen pistas valiosas sobre la estructura de la base de datos.
cadena comparable en java
- Identifique una entrada vulnerable: El atacante encuentra un campo de entrada como una barra de búsqueda o un parámetro de URL que interactúa directamente con la base de datos sin una desinfección adecuada de la entrada.
- Inyecte una carga útil maliciosa: El atacante inyecta un carácter especial (como una comilla simple
') o una función que se sabe que causa un error en la base de datos. - Analizar el error: La base de datos que no puede procesar la consulta con formato incorrecto devuelve un mensaje de error detallado. Este mensaje puede revelar información crucial como:
- El sistema de base de datos (por ejemplo, MySQL Oracle SQL Server).
- La versión de la base de datos.
- La consulta SQL completa que se está ejecutando.
- Errores de sintaxis específicos que se pueden utilizar para comprender los nombres de tablas o columnas.
- Refinar el ataque: Utilizando la información recopilada del mensaje de error, el atacante puede refinar su carga útil para extraer más datos, como nombres de usuario y contraseñas.
Ejemplo:
Paso 1: configure su entorno
- Inicie DVWA. Por lo general, se accede navegando a una URL como
http://localhost/dvwaen tu navegador.
- Inicie sesión en DVWA con las credenciales predeterminadas:
admin/password.
- Vaya a la pestaña Seguridad DVWA y establezca el nivel de seguridad en bajo. Esto garantizará que las vulnerabilidades sean fáciles de explotar.
Paso 2: identificar la vulnerabilidad
La página Inyección SQL tiene un cuadro de entrada simple donde puede ingresar una ID de usuario. La consulta de backend probablemente sea algo así comoSELECT * FROM users WHERE id = 'user_input'
- Ingrese una identificación válida como
1en el cuadro de entrada y haga clic en "Enviar". Debería ver los detalles del usuario con ID 1.
Fuente de inyección SQL
PHP $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( ''
. ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ode ?> - Ahora intenta romper la consulta. Introduzca una cotización única
'en el cuadro de entrada y enviar.
La consulta se convierte en:
SELECT * FROM users WHERE id = ''';Aquí la base de datos ve una cotización adicional y no sabe cómo completar la consulta.
parseint java
En lugar de mostrarle los detalles del usuario, la aplicación devolverá un error de SQL (algo como 'Tiene un error en su sintaxis SQL...')
Esto se llama inyección SQL basada en errores porque:
- El atacante envía una entrada no válida (
') - La base de datos arroja un error.
- Ese error filtra información útil sobre la base de datos (como el tipo de base de datos, el número de estructura de columnas, etc.)
2. Inyección SQL basada en unión
La inyección SQL basada en unión es una técnica en la que los atacantes utilizan elUNIONoperador para combinar los resultados de dos o másSELECTdeclaraciones en un único conjunto de resultados. Esto puede permitirles extraer información de otras tablas de la base de datos. ElUNIONEl operador solo se puede utilizar si:
- Ambas consultas tienen el mismo número de columnas.
- Las columnas tienen tipos de datos similares.
- Las columnas están en el mismo orden.
Operador UNIÓN : ElUNIONEl operador se utiliza para combinar el conjunto de resultados de dos o más.SELECTdeclaraciones.
- Cada
SELECTdeclaración dentroUNIONdebe tener el mismo número de columnas - Las columnas deben tener tipos de datos similares.
- Las columnas deben estar en el mismo orden.
SELECT column_name(s) FROM table1UNIONSELECT column_name(s) FROM table2Ejemplo:
Paso 1: En primer lugar, tenemos que encontrar el número de columnas de la tabla existente en el sitio web para inyectar la inyección SQL basada en UNION:
La página Inyección SQL tiene un cuadro de entrada simple donde puede ingresar una ID de usuario. La consulta de backend probablemente sea algo así como
SELECT * FROM users WHERE id = 'user_input'Ahora intenta romper la consulta. Introduzca una cotización única'en el cuadro de entrada y enviar.
Si la aplicación es vulnerable, recibirá un mensaje de error detallado. Podría verse algo como:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
Paso 2: Utilice elUNIONPalabra clave para descubrir el número de columnas
Para usar elUNIONpalabra clave (un siguiente paso común) necesita saber el número de columnas en la consulta original. Puedes averiguarlo utilizando elORDER BYcláusula
'abc's en números'
- Intenta ordenar los resultados por columna.
1:1 ORDER BY 1.
- Entregar. Debería funcionar.
Fuente de inyección SQL
PHP if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( ''
. ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ?> - Incrementar el número:
1 ORDER BY 2. Entregar. Debería funcionar.
- Continúe incrementando hasta que obtenga un error. Por ejemplo
1 ORDER BY 4podría darte:Unknown column '4' in 'order clause' - Esto significa que la consulta tiene 3 columnas.
3. Inyección SQL ciega
Inyección SQL ciega ocurre cuando los atacantes no pueden ver los resultados de la consulta directamente en la página web. En lugar de eso, infieren información a partir de cambios sutiles en el comportamiento o el tiempo de respuesta de la aplicación. Aunque es más lento y tedioso que el SQLi clásico, puede ser igualmente eficaz.
En lugar de recuperar datos, el atacante infiere información observando el comportamiento de la página web. Por lo general, esto se hace de dos maneras:
- SQLi ciego basado en booleanos: El atacante inyecta una consulta SQL que devuelve un verdadero o FALSO resultado. La respuesta de la aplicación web cambia según si la consulta es verdadera o falsa. Por ejemplo, la página podría mostrar un mensaje diferente o presentar un diseño diferente.
- SQLi ciego basado en tiempo: El atacante inyecta una consulta SQL que hace que la base de datos realice una acción que requiere mucho tiempo (como una
SLEEP()función) si se cumple una condición. El atacante observa el tiempo que tarda la página en cargarse para determinar si la condición inyectada era verdadera o falsa.
Ejemplo:
Imagine una página de inicio de sesión donde ingresa un nombre de usuario y contraseña. La aplicación construye una consulta SQL como esta:
SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input'Una inyección SQL ciega implicaría manipular eluser_inputcampo para hacer una pregunta a la base de datos.
En lugar de obtener una respuesta directa, el atacante podría intentar algo como esto:
user_input = 'admin' AND 1=1; --Si la página se carga normalmente, el atacante sabe que1=1es un verdadero declaración.
user_input = 'admin' AND 1=2; --Si la página muestra un error o se comporta de manera diferente, el atacante sabe que1=2es un FALSO declaración.
Al utilizar una serie de estas preguntas de verdadero/falso, un atacante puede adivinar y extraer información sistemáticamente, un carácter a la vez. El proceso se puede automatizar para adivinar todo, desde nombres de tablas hasta contraseñas de usuario.
Impacto de los ataques de inyección SQL
- Acceso no autorizado a datos sensibles : Los atacantes pueden recuperar información financiera personal o confidencial almacenada en la base de datos.
- Problemas de integridad de datos : Los atacantes pueden modificar, eliminar o corromper datos críticos que afecten la funcionalidad de la aplicación.
- Escalada de privilegios : Los atacantes pueden eludir los mecanismos de autenticación y obtener privilegios administrativos.
- Tiempo de inactividad del servicio : La inyección SQL puede sobrecargar el servidor provocando una degradación del rendimiento o fallas del sistema.
- Daño a la reputación : Un ataque exitoso puede dañar gravemente la reputación de una organización y provocar la pérdida de la confianza del cliente.
Prevención de ataques de inyección SQL
Existen varias prácticas recomendadas para prevenir ataques de inyección SQL:
1. Utilice declaraciones preparadas y consultas parametrizadas
Las declaraciones preparadas y las consultas parametrizadas garantizan que las entradas del usuario se traten como datos y no como parte de la consulta SQL. Este enfoque elimina el riesgo de inyección SQL.
Ejemplo en PHP (usando MySQLi):
$stmt = $conn->prepare('SELECT * FROM users WHERE username = ? AND password = ?'); $stmt->bind_param('ss' $username $password); $stmt->execute();2. Emplear procedimientos almacenados
Los procedimientos almacenados son consultas SQL predefinidas almacenadas en la base de datos. Estos procedimientos pueden ayudar a prevenir la inyección de SQL porque no construyen consultas SQL de forma dinámica.
ejemplo de java hola mundo
Ejemplo:
CREATE PROCEDURE GetUserByUsername (IN username VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = username; END;3. Validación de entrada de lista blanca
Asegúrese de que las entradas del usuario se validen antes de usarse en consultas SQL. Solo permita ciertos caracteres y patrones, como la entrada alfanumérica, para campos como nombres de usuario o direcciones de correo electrónico.
4. Utilice marcos ORM
Marcos de mapeo relacional de objetos (ORM) como Hibernar o Marco de entidad puede ayudar a prevenir la inyección de SQL al manejar automáticamente la generación de consultas, evitando la construcción dinámica de consultas.
5. Restringir los privilegios de la base de datos
Otorgue los permisos de base de datos mínimos requeridos a los usuarios. Asegúrese de que las aplicaciones solo puedan realizar las acciones necesarias (por ejemplo, SELECCIONAR INSERTAR) y restringir permisos como DROP TABLE o ALTER.
6. Manejo de errores
Configure la base de datos y la aplicación para no mostrar mensajes de error detallados al usuario. En su lugar, registre los errores internamente y muestre mensajes de error genéricos a los usuarios finales.