Inyección SQL: Guía para Desarrolladores Oracle
Inyección SQL: Guía para Desarrolladores Oracle
Enero de 2004
INTEGRIGIA INTEGRIGIA
AppSentry e Integrigy son marcas comerciales de Integrigy Corporation. Este documento también puede contener marcas
registradas, marcas comerciales, marcas de servicio y/o nombres comerciales propiedad de sus respectivas empresas u
organizaciones. Integrigy Corporation no se responsabiliza de especificar a qué empresas u organizaciones pertenecen las marcas
que los componen.
Si tiene algún comentario o sugerencia sobre este documento, envíelo por correo electrónico a alerts@[Link].
Integrigy Corporation es líder en seguridad de aplicaciones para grandes empresas y aplicaciones de misión crítica.
Nuestra herramienta de evaluación de vulnerabilidades de aplicaciones, AppSentry, ayuda a las empresas a proteger sus
aplicaciones más importantes y de mayor tamaño. Integrigy Consulting ofrece servicios de evaluación de seguridad para las
principales aplicaciones ERP y CRM.
Integrigy Corporation
2052 Lincoln Park West, Suite 1301
Chicago, Illinois 60614 EE. UU.
888/5424802
[Link]
Tabla de contenido
1. Introducción..............................................................4
Resumen ...................................................................................4
Descripción general de la inyección SQL ............................................................4
Inyección SQL: Oracle frente a otras bases de datos...........................4
Desarrollo de aplicaciones ..........................................................5 2.
Inyección SQL............................................................6
Introducción ..............................................................................6 Categorías
de ataques de inyección SQL ..........................................6
Vulnerabilidades .....................................................................7
Excepciones..............................................................7 3. Métodos de
inyección SQL.............................................8 Manipulación de
SQL.....................................................................8 Inyección de
código...........................................................................9 Inyección de
llamadas a funciones............................................................10
Desbordamientos de búfer......................................................................11
4. PL/SQL...................................................................12
Resumen..................................................................................12 Ejecutar
sentencia inmediata..................................................12
Paquete DBMS_SQL ..............................................................14 Cursores
dinámicos.....................................................................15 5.
JDBC ......................................................................16 Descripción
general..................................................................................16
PreparedStatement...................................................................16
CallableStatement....................................................................17 6. Protección
1
Introducción
Resumen
La mayoría de los desarrolladores de aplicaciones subestiman el riesgo de ataques de inyección SQL contra
aplicaciones web que utilizan Oracle como base de datos. Nuestras auditorías de aplicaciones web personalizadas muestran
que muchos desarrolladores no comprenden del todo el riesgo de los ataques de inyección SQL ni las técnicas básicas
para prevenirlos.
Este documento está dirigido a desarrolladores de aplicaciones, administradores de bases de datos y auditores de
aplicaciones para destacar el riesgo de los ataques de inyección SQL y demostrar por qué las aplicaciones web
pueden ser vulnerables. No pretende ser un tutorial sobre cómo ejecutar ataques SQL ni proporciona instrucciones
para llevar a cabo dichos ataques.
La inyección SQL es un ataque básico que se utiliza para obtener acceso no autorizado a una base de datos o para
recuperar información directamente de ella. Los principios de la inyección SQL son sencillos y este tipo de ataques son
fáciles de ejecutar y dominar.
Creemos que las aplicaciones web que utilizan Oracle como base de datos son más vulnerables a los ataques de
inyección SQL de lo que la mayoría de los desarrolladores piensan. Nuestras auditorías han detectado numerosas
aplicaciones web vulnerables a la inyección SQL, incluso cuando se implementaron estándares de codificación bien
establecidos durante su desarrollo. Los ataques de inyección SQL basados en funciones son los que más preocupan, ya
que no requieren conocimiento de la aplicación y pueden automatizarse fácilmente.
Afortunadamente, los ataques de inyección SQL son fáciles de combatir con prácticas de codificación sencillas. Sin embargo,
Cada parámetro que se pase a cada instrucción SQL dinámica debe ser validado o se deben usar variables de enlace.
Oracle generalmente ha demostrado ser eficaz contra los ataques de inyección SQL, ya que no admite múltiples sentencias
SQL (a diferencia de SQL Server y PostgreSQL), no cuenta con la sentencia EXECUTE (SQL Server) ni con la
función INTO OUTFILE (MySQL). Además, el uso de variables de enlace en entornos Oracle, por motivos de rendimiento,
proporciona una sólida protección contra este tipo de ataques.
Oracle ofrece una protección más sólida e inherente contra los ataques de inyección SQL que otras bases de datos;
sin embargo, las aplicaciones que carecen de las defensas adecuadas contra este tipo de ataques pueden
ser vulnerables. A pesar de estas ventajas, muchas aplicaciones web son vulnerables a los ataques de inyección SQL.
Desarrollo de aplicaciones
Las aplicaciones pueden desarrollarse utilizando diversos métodos para conectarse a una base de datos Oracle;
algunos de estos métodos son más vulnerables a los ataques de inyección SQL que otros. Este artículo se centrará
en algunos lenguajes de programación y arquitecturas de aplicaciones comúnmente utilizados para aplicaciones
web, si bien las técnicas descritas deberían ser relevantes para la mayoría de los lenguajes de
programación y arquitecturas de aplicaciones.
Este artículo se centra en las aplicaciones que utilizan JDBC para conectarse a una base de datos Oracle y
PL/SQL como lenguaje de programación. Consideramos que estos son los dos métodos de programación más
comunes para aplicaciones que utilizan Oracle como base de datos.
2
Inyección SQL
Introducción
Los ataques de inyección SQL son simples en su naturaleza: un atacante introduce una cadena de texto en una aplicación con la
esperanza de manipular la instrucción SQL en su beneficio. La complejidad del ataque radica en explotar una instrucción SQL que el
atacante puede desconocer. Código abierto
Las aplicaciones y las aplicaciones comerciales que se distribuyen con código fuente son más vulnerables, ya que un atacante puede
encontrar declaraciones potencialmente vulnerables antes de un ataque.
Existen cuatro categorías principales de ataques de inyección SQL contra bases de datos Oracle:
1. Manipulación de SQL 2.
Inyección de código 3.
Inyección de llamadas a funciones
4. Desbordamiento de búfer
Las dos primeras categorías, manipulación de SQL e inyección de código, deberían ser bien conocidas por el lector, ya que son los ataques
más comúnmente descritos para todo tipo de bases de datos (incluidas SQL Server, MySQL, ProgressSQL y Oracle).
La manipulación de SQL implica modificar la sentencia SQL mediante operaciones de conjuntos (p. ej., UNION) o alterar la cláusula WHERE
para obtener un resultado diferente. Muchos ataques de inyección SQL documentados son de este tipo. El ataque más conocido consiste
en modificar la cláusula WHERE de la sentencia de autenticación de usuario para que siempre devuelva TRUE.
La inyección de código se produce cuando un atacante inserta nuevas sentencias SQL o comandos de base de datos en la base de datos SQL.
El ataque clásico de inyección de código consiste en añadir un comando EXECUTE de SQL Server a la instrucción SQL vulnerable. La
inyección de código solo funciona cuando se admiten varias instrucciones SQL por solicitud a la base de datos. SQL Server y PostgreSQL
cuentan con esta capacidad y, en ocasiones, es posible inyectar varias instrucciones SQL con Oracle.
Las dos últimas categorías corresponden a ataques más específicos contra bases de datos Oracle y no son muy conocidas ni están bien
documentadas. En la gran mayoría de nuestras auditorías de aplicaciones, hemos encontrado aplicaciones vulnerables a estos dos tipos de
ataques.
La inyección de llamadas a funciones consiste en la inserción de funciones de la base de datos Oracle o funciones personalizadas en
una sentencia SQL vulnerable. Estas llamadas a funciones pueden utilizarse para realizar llamadas al sistema operativo o manipular
datos en la base de datos.
La inyección SQL por desbordamiento de búfer es un subconjunto de la inyección de llamadas a funciones. En varias bases
de datos comerciales y de código abierto, existen vulnerabilidades en algunas funciones que pueden provocar un
desbordamiento de búfer. Si bien existen parches para la mayoría de estas vulnerabilidades, muchas bases de datos en
producción aún no se han actualizado.
¿Qué es vulnerable?
Una aplicación web es vulnerable a la inyección SQL por una sola razón: la entrada de texto del usuario no se valida
correctamente y se pasa a una instrucción SQL dinámica. Normalmente, la entrada de texto se pasa directamente a la
instrucción SQL. Sin embargo, también puede almacenarse en la base de datos y luego pasarse a una instrucción SQL
dinámica. Debido a la naturaleza sin estado de muchas aplicaciones web, es común escribir datos en la base de datos entre
páginas web. Este tipo de ataque indirecto es mucho más complejo y requiere un conocimiento profundo de la aplicación.
Lo que no es vulnerable
Las sentencias SQL que utilizan variables de enlace son generalmente inmunes a los ataques de inyección SQL, ya que la
base de datos Oracle utiliza exclusivamente el valor de la variable de enlace y no interpreta su contenido de ninguna
manera. PL/SQL y JDBC permiten el uso de variables de enlace. Se recomienda su uso generalizado por motivos de
seguridad y rendimiento.
3
Métodos de inyección SQL
Existen cuatro tipos de ataques de inyección SQL que funcionan en bases de datos Oracle. Los dos primeros —
manipulación de SQL e inyección de código— son bien conocidos y están documentados. Sin embargo, la inyección
de llamadas a funciones y los ataques de desbordamiento de búfer no están bien documentados y muchas aplicaciones
son vulnerables a estos tipos de ataques. Todos estos tipos de inyección SQL son válidos para otras bases de datos,
como SQL Server, DB2, MySQL y PostgreSQL.
En este capítulo se utilizan sentencias SQL para demostrar los distintos tipos de métodos de inyección SQL.
Para evitar cualquier dependencia del lenguaje de programación, solo se presentan las sentencias SQL previstas
por el desarrollador y las manipuladas por el atacante. Las partes en azul y cursiva muestran un ejemplo de la
entrada que espera el programador y de lo que un atacante podría introducir en un campo de texto de la
aplicación.
Manipulación de SQL
El tipo más común de ataque de inyección SQL es la manipulación de SQL. El atacante intenta modificar la
sentencia SQL existente añadiendo elementos a la cláusula WHERE o extendiéndola con operadores de conjuntos
como UNION, INTERSECT o MINUS. Existen otras variantes, pero estos son los ejemplos más significativos.
La manipulación clásica de SQL se produce durante la autenticación de inicio de sesión. Una aplicación web
sencilla puede comprobar la autenticación del usuario ejecutando la siguiente consulta y verificando si se
devolvió alguna fila:
SELECCIONAR * DE usuarios
SELECCIONAR * DE usuarios
Según la precedencia de operadores, la cláusula WHERE es verdadera para cada fila y el atacante ha obtenido
acceso a la aplicación.
El operador de conjuntos UNION se utiliza con frecuencia en ataques de inyección SQL. El objetivo es manipular una
Una instrucción SQL puede devolver filas de otra tabla. Un formulario web podría ejecutar la siguiente consulta
para devolver una lista de productos disponibles:
La lista que se devuelve al formulario web incluirá todos los productos seleccionados, pero también todos los usuarios de la base
de datos de la aplicación.
Inyección de código
Los ataques de inyección de código intentan añadir instrucciones o comandos SQL adicionales a una instrucción SQL existente.
Este tipo de ataque se utiliza con frecuencia contra aplicaciones de Microsoft SQL Server, pero rara vez funciona con una
base de datos Oracle. La instrucción EXECUTE en SQL Server es un objetivo frecuente de los ataques de inyección SQL;
no existe una instrucción equivalente en Oracle.
En PL/SQL y Java, Oracle no admite múltiples sentencias SQL por solicitud a la base de datos. Por lo tanto, el siguiente ataque
de inyección común no funcionará contra una base de datos Oracle mediante una aplicación PL/SQL o Java. Esta sentencia
generará un error.
SELECCIONAR * DE usuarios
DONDE username = 'bob' Y PASSWORD = 'mypassword'; ELIMINAR DE users
DONDE nombre de usuario = 'admin';
Sin embargo, algunos lenguajes de programación o API pueden permitir la ejecución de múltiples
sentencias SQL.
Las aplicaciones PL/SQL y Java pueden ejecutar dinámicamente bloques PL/SQL anónimos, que son vulnerables a la
inyección de código. A continuación se muestra un ejemplo de un bloque PL/SQL ejecutado en una aplicación web:
El bloque PL/SQL de ejemplo anterior ejecuta un procedimiento almacenado de la aplicación que cifra y guarda la contraseña
del usuario. Un atacante intentará manipular el bloque PL/SQL para que se ejecute como…
La inyección de llamadas a funciones consiste en la inserción de funciones de la base de datos Oracle o funciones personalizadas en
una sentencia SQL vulnerable. Estas llamadas a funciones pueden utilizarse para realizar llamadas al sistema operativo o manipular
datos en la base de datos.
La base de datos Oracle permite ejecutar funciones, incluidas funciones en paquetes, como parte de una instrucción SQL. Por defecto,
Oracle proporciona más de 1000 funciones en aproximadamente 175 paquetes de base de datos estándar, aunque solo unas pocas
de ellas pueden ser útiles en un ataque de inyección SQL. Algunas de estas funciones realizan actividades de red que pueden ser explotadas.
Cualquier función personalizada o función que resida en un paquete personalizado también puede ejecutarse en una instrucción SQL.
Las funciones que se ejecutan como parte de una instrucción SQL SELECT no pueden modificar la base de datos a menos que estén marcadas
como “PRAGMA TRANSACTION”. Ninguna de las funciones estándar de Oracle se ejecuta como transacción autónoma. Las funciones
que se ejecutan en las instrucciones INSERT, UPDATE o DELETE sí pueden modificar los datos de la base de datos.
Utilizando las funciones estándar de Oracle, un atacante puede enviar información de la base de datos a un equipo remoto o ejecutar otros
ataques desde el servidor de la base de datos. Muchas aplicaciones nativas de Oracle utilizan paquetes de base de datos que pueden
ser explotados por un atacante. Estos paquetes personalizados pueden incluir funciones para cambiar contraseñas o realizar otras
transacciones confidenciales de la aplicación.
El problema con la inyección de llamadas a funciones es que cualquier instrucción SQL generada dinámicamente es vulnerable.
Incluso las sentencias SQL más simples pueden ser explotadas eficazmente.
El siguiente ejemplo demuestra que incluso las sentencias SQL más simples pueden ser vulnerables.
Los desarrolladores de aplicaciones a veces utilizan funciones de base de datos en lugar de código nativo (por ejemplo, Java) para realizar
tareas comunes. Dado que no existe un equivalente directo de la función TRANSLATE en Java, el programador optó por utilizar una
instrucción SQL.
Esta instrucción SQL no es vulnerable a otros tipos de ataques de inyección, pero se puede manipular fácilmente mediante un ataque de
inyección de función. El atacante intenta manipular la instrucción SQL para
ejecutar como –
La instrucción SQL modificada solicitará una página a un servidor web. El atacante podría manipular la cadena y la URL para incluir otras
funciones con el fin de obtener información útil del servidor de base de datos y enviarla al servidor web en la URL. Dado que el servidor
de base de datos Oracle es el más utilizado, el atacante podría experimentar este problema.
Es probable que se encuentre detrás de un cortafuegos, pero también podría utilizarse para atacar otros servidores de la red interna.
Las funciones personalizadas y las funciones incluidas en paquetes personalizados también se pueden ejecutar. Por ejemplo,
una aplicación personalizada podría tener la función ADDUSER en el paquete personalizado MYAPPADMIN. El
desarrollador marcó la función como «PRAGMA TRANSACTION», lo que permite su ejecución bajo cualquier circunstancia
especial que la aplicación pudiera encontrar. Al estar marcada como «PRAGMA TRANSACTION», puede escribir
en la base de datos incluso dentro de una instrucción SELECT.
Al ejecutar la instrucción SQL anterior, el atacante puede crear nuevos usuarios de la aplicación.
Desbordamientos de búfer
Se han identificado desbordamientos de búfer en las funciones estándar de varias bases de datos. Algunas funciones estándar
de Oracle son susceptibles a desbordamientos de búfer, que pueden explotarse mediante un ataque de inyección SQL en una
base de datos sin parches. Existen desbordamientos de búfer conocidos en las funciones estándar tz_offset, to_timestamp_tz
y bfilename.
La mayoría de los servidores de aplicaciones y web no gestionan correctamente la pérdida de conexión a la base de datos
debido a un desbordamiento de búfer. Normalmente, el proceso web se bloquea hasta que se cierra la conexión con el cliente,
lo que convierte esto en un ataque de denegación de servicio muy efectivo.
Se ejecuta un ataque de desbordamiento de búfer utilizando tz_offset, to_timestamp_tz y bfilename utilizando los
métodos de inyección de funciones descritos anteriormente.
4
PL/SQL
Descripción general
Los procedimientos almacenados de la base de datos Oracle se pueden invocar directamente desde PL/SQL Gateway o
mediante la instrucción `callablestatement` de JDBC. PL/SQL Gateway (modplsql) es la extensión de Apache de
Oracle que permite desarrollar aplicaciones web utilizando procedimientos almacenados de la base de datos. Modplsql
se incluye con Oracle9iAS y lo utilizan algunas aplicaciones comerciales.
En PL/SQL, las sentencias SQL se pueden ejecutar de cuatro maneras distintas: (1) SQL embebido, (2) cursores, (3)
sentencias EXECUTE IMMEDIATE o (4) el paquete DBMS_SQL. Las sentencias SQL embebidas y los cursores
estáticos se compilan y solo permiten variables de enlace; sin embargo, los cursores dinámicos pueden ser
vulnerables a ataques de inyección SQL. EXECUTE IMMEDIATE y DBMS_SQL permiten SQL dinámico, por lo que
también son vulnerables a ataques de inyección SQL.
Desde la perspectiva de la inyección SQL, hay poca diferencia entre `DBMS_SQL` y `execute immediate` : ambas
sentencias son igualmente vulnerables. El paquete `DBMS_SQL` es un método antiguo para SQL dinámico y está siendo
reemplazado por la sentencia `execute immediate` . Algunas aplicaciones pueden incluir una combinación de sentencias
`DBMS_SQL` y `execute immediate` .
Para obtener información más detallada, consulte el capítulo “SQL dinámico nativo” en la Guía del usuario y referencia
de Oracle9i PL/SQL.
La instrucción EXECUTE IMMEDIATE se utiliza para ejecutar SQL dinámico en código PL/SQL. Esta instrucción admite
completamente variables de enlace, pero también puede ejecutarse mediante una cadena concatenada.
Una instrucción `execute immediate` susceptible a ataques de inyección SQL podría escribirse así:
...
sql := 'SELECT código postal FROM estados WHERE nombreestado = ''' || nombre || '''';
EJECUTAR SQL INMEDIATO EN el código;
SI el código = 'IL' ENTONCES ...
...
FIN;
Algunos lectores podrían preguntarse si la instrucción SELECT del ejemplo de código anterior tendría sentido
en un ataque de inyección SQL. No se puede explotar fácilmente mediante operaciones de conjuntos (p. ej., UNION)
ni concatenando otra instrucción SQL, ya que esto no está permitido por la directiva EXECUTE IMMEDIATE.
A menos que se utilice un bloque PL/SQL (es decir, BEGIN...END), manipular el resultado de la cláusula WHERE
probablemente no tenga mucho efecto. Sin embargo, esta instrucción se puede explotar fácilmente insertando
funciones estándar de bases de datos (por ejemplo, UTL_HTTP) o funciones conocidas que pueden provocar
desbordamientos de búfer.
Para prevenir la inyección SQL y mejorar el rendimiento de la aplicación, siempre se deben utilizar variables de enlace.
...
sql := 'SELECT códigopostal FROM estados WHERE nombreestado = :nombre';
EJECUTAR SQL INMEDIATO USANDO nombre EN código;
SI el código = 'IL' ENTONCES ...
...
FIN;
La instrucción `execute immediate` también puede utilizarse para bloques PL/SQL anónimos. Estos bloques son más
vulnerables a los ataques de inyección SQL, ya que un atacante puede insertar múltiples comandos PL/SQL
y sentencias SQL.
...
vulnerable
EJECUTAR INMEDIATAMENTE 'BEGIN updatepass('' || value || '''); END;';
no vulnerable
cmd := 'BEGIN updatepass(:1); END;';
EJECUTAR CMD INMEDIATO USANDO valor;
...
FIN;
Paquete DBMS_SQL
El paquete DBMS_SQL permite la ejecución de sentencias SQL dinámicas. Este paquete ha sido generalmente
reemplazado por `execute immediate`, pero aún puede utilizarse en muchas aplicaciones web.
DBMS_SQL es más complejo que execute immediate, pero básicamente realiza la misma función.
Al igual que con la ejecución inmediata, siempre se deben usar variables de enlace en lugar de concatenar la cadena
SQL.
...
sql := 'SELECT códigopostal FROM estados WHERE nombreestado = cursor_name := ''' || nombre || '''';
dbms_sql.open_cursor; DBMS_SQL.PARSE(cursor_name,
sql, DBMS_SQL.NATIVE); DBMS_SQL.DEFINE_COLUMN(cursor_name, 1, code,
10); filas_procesadas := DBMS_SQL.EXECUTE(cursor_name);
DBMS_SQL.CLOSE_CURSOR(cursor_name);
...
FIN;
...
sql := 'SELECT postalcode FROM states WHERE statename = :name'; cursor_name := dbms_sql.open_cursor;
DBMS_SQL.PARSE(cursor_name, sql, DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN(cursor_name, 1, code, 10);
DBMS_SQL.BIND_VARIABLE(cursor_name, ':name', name); rows_processed :=
DBMS_SQL.EXECUTE(cursor_name); DBMS_SQL.CLOSE_CURSOR(cursor_name);
...
FIN;
Cursores dinámicos
PL/SQL permite el uso de cursores estáticos y dinámicos. Las sentencias SQL con cursor se pueden generar
dinámicamente, al igual que las sentencias EXECUTE IMMEDIATE o DBMS_SQL.
...
sql := 'SELECT * FROM states WHERE statename = ''' || nombre || '''';
ABRIR cursor_states PARA sql;
BUCLE
CERRAR estado_cursor;
...
FIN;
Al igual que con execute immediate y DBMS_SQL, una variable de enlace eliminaría cualquier posibilidad de inyección
SQL.
5
JDBC
Descripción general
JDBC (Java Database Connectivity) es una interfaz estándar de Java para conectar aplicaciones
Java con bases de datos relacionales. La mayoría de las arquitecturas de desarrollo Java utilizan JDBC para
conectarse a bases de datos Oracle. Java Server Pages (JSP), Java Servlets y Enterprise Java Beans (EJB)
utilizan JDBC para la conectividad con bases de datos, al igual que muchas otras arquitecturas de aplicaciones Java.
Por definición, todas las sentencias SQL en una aplicación JDBC son dinámicas. El SQL dinámico se ejecuta con la
interfaz Statement, específicamente con CallableStatement y PreparedStatement.
Subinterfaces. Desde la perspectiva de la inyección SQL, tanto la interfaz CallableStatement como
la PreparedStatement son vulnerables. En Oracle, una llamada a PreparedStatement ejecuta una única instrucción
SQL . Otras bases de datos (p. ej., SQL Server) admiten la ejecución de varias instrucciones SQL en una sola
llamada.
Declaración preparada
La interfaz PreparedStatement se utiliza para ejecutar sentencias SQL dinámicas. Se puede usar la interfaz
PreparedStatement estándar de JDBC o la interfaz OraclePreparedStatement si se requieren tipos de datos
específicos de Oracle u otras extensiones de Oracle.
Una sentencia preparada vulnerable a la inyección SQL podría tener un aspecto similar a este:
[Link]();
[Link]();
PreparedStatement pstmt =
[Link] ("insert into EMP (ENAME) values (?)");
[Link]();
[Link]();
Declaración invocable
La interfaz CallableStatement se utiliza para ejecutar procedimientos almacenados PL/SQL y bloques PL/SQL anónimos.
Se puede usar la interfaz CallableStatement estándar de JDBC o la interfaz CallableStatement de Oracle si se
requieren tipos de datos específicos de Oracle u otras extensiones de Oracle.
La llamada anónima a un bloque PL/SQL es mucho más vulnerable a los ataques de inyección SQL, ya que se pueden insertar
múltiples sentencias SQL y comandos PL/SQL.
6
Protección contra la inyección SQL
Los ataques de inyección SQL se pueden contrarrestar fácilmente con simples cambios en la programación; sin embargo, los
desarrolladores deben ser lo suficientemente rigurosos como para aplicar los siguientes métodos a cada procedimiento y función
accesible desde la web. Es fundamental proteger cada instrucción SQL dinámica. Una sola instrucción SQL sin protección puede
comprometer la aplicación, los datos o el servidor de la base de datos.
Variables de enlace
La protección más eficaz contra los ataques de inyección SQL es el uso de variables de enlace. Su uso también mejora el rendimiento
de las aplicaciones. Los estándares de codificación de aplicaciones deberían exigir el uso de variables de enlace en todas las
sentencias SQL. Ninguna sentencia SQL debería crearse concatenando cadenas y parámetros.
Las variables de enlace deben usarse en todas las sentencias SQL, independientemente de cuándo o dónde se ejecuten.
Este es el estándar de codificación interno de Oracle y también debería ser el estándar de su organización. Un
ataque de inyección SQL muy complejo podría explotar una aplicación almacenando una cadena de ataque en la base de datos,
que posteriormente se ejecutaría mediante una instrucción SQL dinámica.
declaración.
Los capítulos anteriores sobre PL/SQL y JDBC demostraron cómo usar eficazmente las variables de enlace para eliminar las
vulnerabilidades de inyección SQL. El uso de variables de enlace es sencillo, pero requiere al menos una línea de código adicional
por variable. Dado que una instrucción SQL típica utiliza entre 10 y 20 valores, el esfuerzo de codificación adicional puede
ser considerable.
En raras ocasiones, un desarrollador debe crear dinámicamente una instrucción SQL. Estas excepciones se detallan en el
siguiente capítulo.
Validación de entrada
Es necesario validar todos los parámetros de cadena que se pasen. Muchas aplicaciones web utilizan campos ocultos y otras
técnicas, que también deben validarse. Si no se utiliza una variable de enlace, los caracteres especiales de la base de datos deben
eliminarse o escaparse.
En las bases de datos Oracle, el único carácter problemático es la comilla simple. El método más sencillo consiste en escapar todas
las comillas simples, ya que Oracle interpreta las comillas simples consecutivas como una comilla simple literal.
No se recomienda usar variables de enlace y escapar comillas simples para la misma cadena. Una variable de enlace
almacena la cadena de entrada exacta en la base de datos, mientras que escapar comillas simples genera comillas dobles.
Seguridad funcional
Las funciones de bases de datos, tanto estándar como personalizadas, pueden ser explotadas en ataques de inyección SQL.
Muchas de estas funciones pueden utilizarse eficazmente en un ataque. Oracle incluye cientos de funciones estándar
y, por defecto, todas tienen permisos de acceso público (PUBLIC). La aplicación puede contener funciones adicionales que
realizan operaciones como cambiar contraseñas o crear usuarios, las cuales podrían ser explotadas.
Deben restringirse todas las funciones que no sean absolutamente necesarias para la aplicación.
El capítulo 8 proporciona información detallada sobre cómo determinar las funciones a las que un usuario de la base de
datos puede acceder y las funciones que deben restringirse.
Mensajes de error
Si un atacante no puede obtener el código fuente de una aplicación, los mensajes de error se vuelven cruciales para el éxito
del ataque. La mayoría de las aplicaciones Java no devuelven mensajes de error detallados.
Deben realizarse pruebas y análisis para determinar si la aplicación devuelve mensajes de error detallados.
La pasarela PL/SQL se puede configurar para mostrar distintos niveles de mensajes de error. Cuanta más información
contenga un mensaje de error, más útil resultará para un atacante. Todas las aplicaciones de pasarela PL/SQL deben diseñarse
para devolver una página de error generada por la aplicación cuando se produzca un error de Oracle, en lugar de permitir
que la pasarela devuelva un mensaje de error.
Sin embargo, algunos errores, como el de procedimiento no encontrado, deben ser devueltos por la puerta de
enlace. La configuración de ERROR_STYLE en el archivo de configuración de «[Link]» determina el nivel de información
que se devuelve al usuario. Dado que este tipo de errores probablemente se deban a un ataque y no a errores en el
procesamiento normal de la aplicación, se debe devolver información mínima o ninguna. El parámetro ERROR_STYLE debe
configurarse como «WebServer» en lugar de «Gateway» o «GatewayDebug».
ERROR_STYLE se puede configurar tanto a nivel global como a nivel DAD, por lo que deben revisarse ambas secciones del
archivo de configuración.
7
Excepciones comunes
En PL/SQL y Java, se recomienda usar variables de enlace para todas las sentencias SQL dinámicas. Sin
embargo, en raras ocasiones no es posible utilizarlas.
Al generar una instrucción SQL dinámica, no se pueden usar variables de enlace para los nombres de tablas ni
columnas. Los nombres de objetos de base de datos válidos (es decir, nombres de tablas y columnas) solo
pueden contener caracteres alfanuméricos y los símbolos de subrayado (_), dólar ($) y almohadilla (#). Las comillas
(simples y dobles) y otros caracteres especiales no son válidos.
Cualquier nombre de tabla o columna dinámico debe ser validado y todos los caracteres no válidos deben ser
eliminados de la cadena.
En PL/SQL, la función TRANSLATE se puede utilizar para eliminar fácilmente caracteres no válidos de un nombre
de objeto.
traducir(mayúsculas(<cadena de entrada>),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_#$@. `~!%^*()=+{}[];":''?/><,|\',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_#$@.');
Cláusulas similares
Las variables de enlace son válidas en una cláusula LIKE y deben usarse. % y _ Los personajes deben ser directamente
se añade a la cadena en lugar de concatenar la instrucción SQL.
En cambio, se requieren varias instrucciones y una variable de enlace para crear correctamente la instrucción SQL.
pstmt = [Link]("SELECT id FROM users WHERE name LIKE ?"); [Link] (1, name);
Al generar una llamada a un procedimiento o función dinámica, no se puede usar una variable de enlace para el nombre
del procedimiento o función. Los nombres de objetos de base de datos válidos (nombres de procedimientos y funciones)
solo pueden contener caracteres alfanuméricos y los símbolos de subrayado (_), dólar ($) y almohadilla (#).
El punto (.) y la arroba (@) se utilizan para especificar nombres de paquetes y enlaces a bases de datos. Las comillas
(simples y dobles) y otros caracteres especiales no son válidos.
Cualquier procedimiento o función llamada dinámicamente debe ser validada y todos los caracteres no válidos deben
ser eliminados de la cadena.
En PL/SQL, la función TRANSLATE se puede utilizar para eliminar fácilmente caracteres no válidos de un nombre de
objeto.
traducir(mayúsculas(<cadena de entrada>),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_#$@. `~!%^*()=+{}[];":''?/><,|\',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_#$@.');
8
Funciones de Oracle
Por defecto, Oracle proporciona más de 1000 funciones en aproximadamente 175 paquetes de bases de datos estándar. La mayoría
de estas funciones tienen permisos PUBLIC.
Todas las funciones disponibles para PUBLIC se pueden encontrar con la siguiente consulta:
seleccionar *
No se puede restringir el acceso a funciones específicas dentro de un paquete; solo se puede restringir el acceso al paquete completo.
Para revocar el acceso PÚBLICO a un paquete, utilice el siguiente comando SQL como base de datos privilegiada.
usuario –
Funciones estándar
Se han detectado desbordamientos de búfer en tres funciones estándar de la base de datos Oracle: bfilename, TZ_OFFSET
y TO_TIMESTAMP_TZ. Estas funciones se encuentran en el paquete de base de datos STANDARD y no existe forma de restringir
su acceso. Para detener los ataques de desbordamiento de búfer, debe aplicar los parches descritos en las alertas de seguridad
de Oracle n.° 48, 49 y 50.
Oracle proporciona cientos de funciones en paquetes de bases de datos estándar. Muchos de estos paquetes tienen los
prefijos DBMS_ y UTL_.
Se deben revisar los siguientes paquetes. Si la aplicación no utiliza el paquete, se debe restringir el acceso.
Prueba de DBMS_JAVA
BLOQUEO DE LA BASE DE DATOS
Tubería DBMS
DBMS_ALEATORIO
ARCHIVO_UTL
UTL_HTTP
UTL_SMTP
UTL_TCP
Puede encontrar información adicional sobre los paquetes suministrados por Oracle en la Referencia de paquetes
PL/SQL suministrados por Oracle9i.
Las funciones y las funcionalidades incluidas en los paquetes escritos para la aplicación también pueden ser explotadas mediante un
ataque de inyección SQL.
9
Referencias
“Uso de funciones de bases de datos en ataques de inyección
SQL” [Link]