Cómo evitar inyección SQL en PHP

Creeme a todos nos pasa, a mi después de años de práctica me pasó en más de una ocasión, la causa... ¡descuido absurdo!.

La inyección de código malicioso en la base de datos es un problema que casi todos hemos padecido en algún momento, especialmente cuando somos nuevos y no consideramos la posibilidad de que alguien se tome la molestia de hacernos pasar horas o días de agonía.

Creeme a todos nos pasa, a mi después de años de práctica me pasó en más de una ocasión, la causa... ¡descuido absurdo!.

Para prevenir la inyección de código debes sanear el contenido, probar la eficiencia de tu código y hacer los ajustes necesarios antes que este (el contenido) llegue a la base de datos, con PHP esto es posible si te pegas a prácticas seguras.

Eliminemos etiquetas de script sospechosas

Si el área de texto de tu Sistema de Manejo de Contenido utiliza un editor enriquecido como TinyMCE, este tiende a enviar el contenido con las etiquetas de estructura HTML que utilizas para crear el contenido; a decir <p><ul><table> etc. pero nunca encontrarás etiquetas como <script> o <?php ?>, no hay forma en la que estás deban transportarse en tu contenido al menos que estés escribiendo sobre ellas en algún ejemplo como lo es este artículo.

Decide cuidadosamente qué etiquetas HTML si deseas en tu contenido, utiliza la función strip_tags(). para retirar todas las etiquetas HTML y PHP de una cadena de texto.

 

 

El ejemplo anterior se verá como texto limpio sin etiquetas en la vista de código del navegador de tu elección (el mio es Chrome) Pero ojo, no todo es sacudirse las etiquetas, si el documento contiene múltiples párrafos, listas y encabezados, terminarás con una cadena de texto sin posibilidad de formato alguno porque ya no hay elementos de diferenciación de contenido.

Para eliminar las etiquetas maliciosas y dejar las inofensivas, pasamos al segundo parámetro de esta función.

 

 

Si analizas en la vista de código de tu navegador verás que ahora el contenido incluye las etiquetas de párrafo y la ancla:

<p>Esto es un ejemplo con una <a href=”#”>liga integrada</a></p>

Este paso es importante como primer barrera de protección. Recomendada su utilización, a la creación de este artículo, strip_tags() es compatible y segura con versiones PHP a partir de 5.3.4 a 7.4.0 y hasta donde sea soportado, es una de esas funciones que encajan en el dicho “SI NO ESTÁ ROTO PARA QUÉ ARREGLARLO”


Convertir todo lo que se pueda en entidades HTML

 

Ya eliminamos y filtramos etiquetas HTML, ahora para conservar la guardia arriba, convertimos las comillas y caracteres especiales en entidades HTML. Para esto PHP cuenta con dos funciones que hacen casi lo mismo htmlspecialchars() y htmlentities(), la segunda es más funcional que la primera, porque htmlspecialchars() codifica una un pequeño set de caracteres problemáticos, como los caracteres latinos con tilde y apostrofe. En cambio htmlentities() abarca cualquier carácter que tenga su equivalente en entidad HTML.

Si tomamos el ejemplo ya procesado de strip_tags() y le agregamos htmlentities(), se verá así.

 


Lo que veremos en la vista de código del navegador será:

 
&lt;p&gt;El ni&ntilde;o est&aacute; llorando &lt;a href=&quot;#&quot;&gt;por qu&eacute; ser&aacute;&lt;/a&gt;&lt;/p&gt;gt;

Como puedes ver, absolutamente todas las etiquetas, caracteres latinos y comillas, fueron transformadas en entidades HTML. Si por casualidad en la primer función no logramos desmantelar alguna etiqueta de código, aquí la inoculamos por completo.

Aun así no estamos fuera del agua y los tiburones son merodeadores, ya que no existe tal cosa como demasiado precavido, debemos ir un poco más allá.

Las comillas siempre son un problema, ¿cómo resolvemos esto?
Una máscara de bits de alguno de los siguientes indicadores que especifican cómo manejar comillas es la solución perfecta, la que PHP utiliza por defecto es ENT_COMPAT, tu decide, esta es la lista:

ENT_COMPAT Convertirá comillas dobles y dejará solo comillas simples.
ENT_QUOTES Convertirá tanto comillas dobles como simples.
ENT_NOQUOTES Dejará las comillas dobles y simples sin convertir.

Nunca utilices ENT_IGNORE, el uso de esta bandera ya que puede traer serios problemas de seguridad .

EL procedimiento más efectivo es este:

 

 

La importancia de las Sentencias Preparadas (prepared Statements)

 

Si trabajas con PHP seguramente utilizas MySQL o SQLite, al acceder a cualquier base de datos, tienes dos opciones, MySQLi y PDO. No te hablaré de cual es mejor soportado, más estable o del desempeño de estos dos controladores, ambos soportan métodos procedurales y sentencias preparadas.

Hay dos grandes beneficios en el uso de las sentencias preparadas. La primera es que las consultas sólo necesitan analizarse una vez, y se puede ejecutar infinidad de veces con los mismos parámetros o con distintos, esto hace muy rápida su ejecución. La segunda ventaja es la capacidad de compilar y optimizar su plan para ejecutar la consulta…

Un ejemplo de sentencia preparada es este:

 

 

 

Este de arriba es un ejemplo simple de procedimiento pero muy seguro, para novatos e intermedios que comienzan con el manejo de back end, no puedo insistir lo suficiente al decirles que la seguridad es algo a considerar antes y después de cada proyecto.

Digamos que no eres un experto (ni yo lo soy) no te angusties, nadie es completamente un experto hasta que no recibe el último golpe y aprende cómo esquivarlo la próxima vez.

Si implementas estas recomendaciones, estarás bien, espero que esto te ayude a resolver algún problema que se te ha presentado. Hay muchas formas de desplumar una gallina, yo me voy por la más rápida y segura.


Recapitulando:

Filtra todo

Erradica cualquier tipo de etiqueta HTML o PHP que provenga de las peticiones HTTP, provenga de POST o de GET, ambos métodos llegarán a donde mismo a hacer lo mismo

Estandariza todas tus etiquetas

Convierte a entidades HTML todo lo que representa un riesgo como corchetes, angulares, cuñas y comillas (dobles y sencillas) No tiene sentido dar paso a posibilidades remotas pero riesgosas.

Has todas tus peticiones preparadas

Todas, el CRUD completo, INSERT - SELECT - UPDATE y DELETE.


Siguiendo estas recomendaciones, puedes estar tranquilo que has levantado una muralla perimetral difícil de saltar o derribar.

Si tienes alguna duda o comentario eres bienvenido.