\documentclass[12pt, a4paper]{article} \usepackage[spanish]{babel} \title{Inyección SQL} \author{Nicolás A. Ortega Froysa} \begin{document} \maketitle \section{Introducción} Una \textit{inyección SQL} es una especie de ataque cibernético en que se inyecta código SQL malicioso en una entrada de datos de un formulario. De esta forma, el atacante puede correr peticiones arbitrarias en la base de datos, y así conseguir información de ella, insertar información errónea, corromper los datos, o incluso borrar información importante. Es un ataque común en sistemas web que hacen uso de una base de datos, y especialmente cuando permiten interacción (indirecta) entre el usuario y la base de datos (e.g.\ formularios de entrada). \section{Peticiones SQL Erróneas} Cuando se escribe una petición SQL, se hace combinando en una misma sentencia los datos y los comandos. A menudo, cuando se crean aplicaciones que interactuan con una base de datos, las entradas de los formularios se insertan \textit{verbatim} en la petición SQL. Cuando ocurre esto, un mal actor puede aprovecharse para inyectar un carácter de escape, y luego correr los comandos que quiera (i.e.\ ejecución de código arbitrario). Por ejemplo, imaginemos un comando SQL que busque si existe un determinado usuario (asumimos que \texttt{PASSWD()} hace el \textit{hash}): \begin{verbatim} SELECT * FROM Users WHERE username="nortega" AND password=PASSWD("MyPasswd"); \end{verbatim} Esto, normalmente sólo escogería la entrada del usuario \textit{nortega}, y sus datos. Mas, si uno quisiera conseguir todos los datos de todos los usuarios, podría insertar en el formulario de usuario: \texttt{nortega"\ OR 1=1; --}. Al hacer esto, el comando terminaría siendo: \begin{verbatim} SELECT * FROM Users WHERE username="nortega" OR 1=1; -- AND password=PASSWD("MyPasswd"); \end{verbatim} Por lo tanto, la contraseña quedaría ignorada (como comentario), y como la condición \texttt{1=1} siempre es verdad, terminaría por devolver todas las entradas de la tabla \texttt{Users}. Para evitar esto, se pueden user ciertas funciones en lenguajes como PHP (e.g. \texttt{mysqli\_escape\_string()}) para \textit{escapar} aquellos caracteres que puedan usarse para hacer este tipo de inyecciones (e.g.\ añadiendo un \texttt{\textbackslash} antes del carácter para escapar el \textit{string}). Entonces el comando pasaría a ser lo siguiente: \begin{verbatim} SELECT * FROM Users WHERE username="nortega\" OR 1=1; --" AND password=PASSWD("MyPasswd"); \end{verbatim} \section{Inyección SQL Ciega} Similarmente al caso anterior, la inyección ciega ocurre cuando la página o aplicación no muestra directamente la información de la base de datos, pero sí se mostraría de manera diferente cuando se cumple una condición. Por ejemplo, con el mismo código del caso anterior, si suponemos que el código se ejecuta en un formulario de \textit{login}, si el número de entradas es igual a 1, entonces acepta entrada en la cuenta. En cuyo caso, con añadir la condición \texttt{LIMIT 1}, ya entraría en la primera cuenta que encuentra (que normalmente es la cuenta del administrador). \begin{verbatim} SELECT * FROM Users WHERE username="nortega" OR 1=1 LIMIT 1; -- AND password=PASSWD("MyPasswd"); \end{verbatim} Esto se evita de la misma manera que en la sección anterior. \section{Inyección SQL De Segundo Orden} Supongamos que todos los formularios vienen con salvaguardas para evitar las inyecciones SQL. Aún así, es posible implementar un ataque más sutil que no afecte inmediatamente la base de datos, sino que lo afecte luego. En estos casos, la SQL del formulario se ejecuta correctamente, guardando el código SQL inyectado apropiadamente como un dato, para que luego sea usado y ejecutado erróneamente como código SQL. De este modo, podríamos decir que los casos anteriores eran inyecciones de primer nivel, ya que se ejecutaban inmediatamente del formulario, mientras que las inyecciones de segundo nivel son aquellos que se ejecutarán más tarde. \end{document}