Ver índice
PDO – Seguridad en SQLite / MySQL

        Ocultar índice  

   Índice de contenidos
   Instalación en Windows
   Instalación en Ubuntu
   Servidores seguros
   Páginas dinámicas
   Sintaxis básica
   Operaciones
   Arrays
   Formatos de presentación
   Operadores
   Bucles
   Extraer y ord. información
   Funciones
   Ficheros externos
   Imágenes dinámicas
   Gestión de directorios
   Cookies y sesiones
   Clases y objetos
   Ficheros en formato PDF
   Bases de datos MySQL
   PHP y XML
   PDO - Bases SQLite / MySQL
   MySQL a traves de misqli
   Algo de JavaScript y AJAX


Inyección de código

El hecho de utilizar los recursos PHP Data Objects no excluye los riesgos de seguridad derivados de lo que llamábamos inyección de código cuando tratábamos de MySQL. Todo lo argumentado allí respecto a los riesgos y vulnerabilidades sigue teniendo plena vigencia tal como puedes ver en este ejemplo.

<?php
include('conecta.inc.php');
$dbMySQL= conecta('ejemploSQLite','MySQL');
$dbSQLite= conecta('ejemploSQLite','SQLite');
$nombre="' or '34=34";
$tabla="demo4";
/* recogemos la cadena tal como viene en la condición WHERE. Por tratarse de una cadena
   tenemos que entrecomillar el nombre de la variable en esa cláusula */
$query= "SELECT Nombre, Apellido1, Apellido2 FROM $tabla WHERE Nombre='$nombre'";
/* esta consulta nos dará como resultado una lista de todos los registros de la tabla.
   Habremos vulnerado las mínimas reglas de seguridad */

   /* primero con el objeto SQLite */
print "Esta es la condición de la consulta: ".$query."<br />";
print "<br /><i>Resultado de la consulta SQLite</i><br />";
if($resultado=$dbSQLite->query($query)){
        print "Estos son los resultados de la consulta en la base de datos SQLite<br /><br />";
        foreach ($resultado as $matriz){
                print $matriz[1]." ".$matriz[2].", ".$matriz[0]."<br />";
        }
}
   /* Igual proceso el objeto MySQL */
print "<br /><i>Resultado de la consulta MySQL</i><br />";
if($resultado=$dbMySQL->query($query)){
        print "Estos son los resultados de la consulta en la base de datos SQLite<br /><br />";
        foreach ($resultado as $matriz){
                print $matriz[1]." ".$matriz[2].", ".$matriz[0]."<br />";
        }
}
?>
Ver ejemplo

Como habrás podido observar una consulta con el código adecuado WHERE Nombre='' or '34=34' muestra la vulnerabilidad y devuelve todos los registros contenidos en la tabla por las mismas razones ya comentadas al estudiar MySQL.

PDO dispone de un método que palía en gran medida este tipo de riesgos. Se trata de:

$variable=$objeto->quote(cadena)

que recoge en $variable el contenido de la cadena incluyéndolo dentro de unas comillas simples'. De esa forma una cadena como ' or '34=34 resultaría transformada en '' or '34=34'

<?php
include('conecta.inc.php');
$dbMySQL= conecta('ejemploSQLite','MySQL');
$dbSQLite= conecta('ejemploSQLite','SQLite');
$nombre="' or '34=34";
/* aplicamos el método quote a la cadena con lo cual el nuevo valor de la variable \$nombre
se entrecomillará de forma automatica */
$nombre=$dbSQLite->quote($nombre);
$tabla="demo4";
/* ya no incluimos la variable \$nombre entre comillas. Ya se las ha asignado el método quote */
$query= "SELECT Nombre, Apellido1, Apellido2 FROM $tabla WHERE Nombre=$nombre";
print "Esta es la condición de la consulta: ".$query."<br />";
/* la consulta ahora ya no listará ninguno de los registros. Habremos mejorado la seguridad */
print "<br /><i>Resultado de la consulta SQLite</i><br />";
if($resultado=$dbSQLite->query($query)){
        print "Estos son los resultados de la consulta en la base de datos SQLite<br /><br />";
        foreach ($resultado as $matriz){
                print $matriz[1]." ".$matriz[2].", ".$matriz[0]."<br />";
        }
}
/* tambien en le caso de MySQL se producirá el resultado esperado */
print "<br /><i>Resultado de la consulta MySQL</i><br />";
if($resultado=$dbMySQL->query($query)){
        print "Estos son los resultados de la consulta en la base de datos SQLite<br /><br />";
        foreach ($resultado as $matriz){
                print $matriz[1]." ".$matriz[2].", ".$matriz[0]."<br />";
        }
}
?>
Ver ejemplo

En cualquier caso los procedimientos anteriores no son los más aconsejables para la realización de consultas seguras. Lo aconsejable en estos casos es utilizar las declaraciones preparadas agregando algunas opciones a las ya comentadas.

A la sintaxis ya conocida:

$actuacion= $objeto->prepare(SENTENCIA)
$actuacion-> execute()

puede hacérsele una modificación incluyendo un nuevo método (bindParam) que tiene como finalidad enlazar el valor de una variable con un identificador incluido en la sentencia SQL. Una sintaxis como esta:

$actuacion= $objeto->prepare('SELECT * FROM tabla WHERE (Nombre=? and Apellido1=?)')
$actuacion-> bindParam(posicion, $variable,tipo, longitud);
$actuacion-> execute()

en la que hacemos las siguientes modificaciones:

Veamos dos ejemplos. El primero de ellos utiliza el método bindParam( mientras que el segundo no lo hace.

Con bindParam Ver código fuente Sin bindParam Ver código fuente

Como habrás podido observar el uso de bindParam impidió la inyección del «código maligno». Desde las páginas oficiales de PHP se recomienda utilizar este método en la situaciones en la que se prevean riesgos de este tipo.

El método bindParam permite algunas modificaciones tales como estas:

$actuacion= $objeto->prepare('SELECT * FROM tabla WHERE (Nombre=:campo_nombre and Apellido1=:campo_apellido) ')
$actuacion-> bindParam(':campo_nombre' , $variable,tipo, longitud);
$actuacion-> execute()

Hemos sustituido cada ? de la sentencia SQL por una palabra cualquiera precedida de : y también el número de posicion (en la llamada al método bindParam) por una cadena (fíjate que va entre comillas) que incluye exactamente el mismo nombre –con los : obligatorios– incluido en la sentencia SQL. Puedes verlo en el ejemplo.

Ver nuevo ejemplo Ver código fuente

Aún disponemos de otra posibilidad alternativa a la anterior. Sería esta:

$actuacion= $objeto->prepare('SELECT * FROM tabla WHERE (Nombre=:campo_nombre and Apellido1=:campo_apellido) ')
$actuacion-> execute(array(':campo_nombre'=>$variable))

En este caso hemos omitido la llamada al método bindParam y cmo alternativa hemos incluido en la llamada al método execute un array asociativo al que asignámos como índices los palabras de la sentencia (siempre precedidas por los dos puntos) y como valor los nombres de la variable que los contiene. Si en la sentencia utilizáramos ? el array habría de ser de tipo escalar. Puedes verlo en los ejemplos.

Ver nuevo ejemplo Ver código fuente Ver nuevo ejemplo Ver código fuente

Como habrás podido observar el «filtro de seguridad» ha funcionado en todos estos ejemplos. Los intentos de visualizar nombre mediante el código ' or '34=34 han fracasado.