Proteger comportamientos del servidor PHP de vulnerabilidades de inyección SQL

Última actualización el 27/04/2021

Problema

Algunas bases de datos permiten enviar varias sentencias SQL en una sola consulta. Por tanto, existen posibles riesgos de seguridad cuando se pasan parámetros en una cadena de consulta a una consulta de base de datos generada dinámicamente.Los hackers podrían intentar modificar variables de URL o de formulario en una consulta dinámica añadiendo instrucciones SQL maliciosas a parámetros existentes.Esta acción suele denominarse ataque de inyección SQL. Es conveniente modificar parte del código de comportamiento del servidor creado por Dreamweaver para reducir el riesgo de ataques de inyección SQL. Para obtener información más detallada sobre la inyección SQL, lea esteartículo de la Wikipedia. (Ref. 201713)

Nota: El problema descrito en esta TechNote se ha solucionado en la actualización de Dreamweaver 8.0.2.

Esta TechNote cubre los comportamientos del servidor PHP de Dreamweaver.Existen TechNotes independientes para los comportamientos del servidor ColdFusion, ASP VBScript, ASP JavaScript y JSP.Los comportamientos del servidor ASP.NET no se ven afectados.

Solución

Al permitir que una cadena de consulta pase un parámetro, asegúrese de que solo se pase la información prevista. Adobe ha creado una actualización de Dreamweaver 8.0.2 que reduce el riesgo de ataques de inyección SQL.Estas correcciones se incorporarán en todas las versiones futuras de Dreamweaver.Después de actualizar Dreamweaver 8, necesitará volver a aplicar los comportamientos del servidor a las páginas que los utilizan y redistribuir esas páginas en su servidor.

El resto de esta TechNote documenta cómo editar manualmente el código de Dreamweaver MX 2004 para prevenir ataques de inyección SQL con el modelo de servidor PHP.Los comportamientos del servidor vulnerables a estos ataques se enumeran a continuación, junto con las correcciones:

Juego de registros con un filtro

No hace falta modificar los juegos de registros sin filtrar; sin embargo, es necesario modificar los juegos de registros filtrados. En el ejemplo siguiente, un conjunto de registros de Dreamweaver MX 2004 llamado "rs_byDate" se filtra por un valor de fecha pasado desde un parámetro de URL.El código resaltado a continuación es lo que se debe cambiar:

<?php $colname_rs_byDate = &quot;1&quot;; if (isset($_GET[&apos;relDate&apos;])) { $colname_rs_byDate = (get_magic_quotes_gpc()) ? $_GET['relDate'] : addslashes($_GET['relDate']); } mysql_select_db($database_dreamqa2, $dreamqa2); $query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = '%s'", $colname_rs_byDate); $rs_byDate = mysql_query($query_rs_byDate, $dreamqa2) or die(mysql_error()); $row_rs_byDate = mysql_fetch_assoc($rs_byDate); $totalRows_rs_byDate = mysql_num_rows($rs_byDate); ?>

Para proteger el conjunto de registros de ataques de inyección SQL, debe crearse una función personalizada GetSQLValueString() cerca de la parte superior de la página.Esta función verifica el tipo de datos del parámetro de consulta.Una vez que se haya creado la función, actualice el código del conjunto de registros para usar la función GetSQLValueString().

Vaya a la segunda línea en la vista de código, justo después del archivo de inclusión para la conexión, y añada la función GetSQLValueString() al principio del código como sigue:

<?php if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") { $theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue); switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } } ?>

Elimine el código de comillas mágicas para que no se agreguen barras invertidas incorrectamente a los datos GET y POST cuando las comillas mágicas están desactivadas en el servidor PHP.

Código original:

$colname_rs_byDate = (get_magic_quotes_gpc()) ?$_GET['relDate'] : addslashes($_GET['relDate']);

Código modificado:

$colname_rs_byDate = $_GET['relDate'];



Actualice el código del conjunto de registros para crear una cadena SQL usando la función GetSQLValueString() creada anteriormente. Actualice el valor de la variable $query_rs_byDate:

Código original:

$query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = '%s'", $colname_rs_byDate);

Código seguro modificado:

$query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = %s", GetSQLValueString($colname_rs_byDate, "date"));

Comportamientos del servidor Insertar, Actualizar y Eliminar registro y asistente de Formulario de inserción de registros

Los comportamientos del servidor Insertar, Actualizar y Eliminar registro y el asistente de Formulario de inserción de registros ya usan la función GetSQLValueString(), por lo que deben refinarse para prevenir inyecciones SQL. Los únicos cambios necesarios están en la función GetSQLValueString().

Aquí está el código original. La línea que se debe cambiar está resaltada en amarillo:

if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") {$theValue = (!get_magic_quotes_gpc()) ? addslashes($theValue) : $theValue; switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } }

Actualizar la definición de la variable $theValue:

Código original:

$theValue = (!get_magic_quotes_gpc()) ? addslashes($theValue) : $theValue;

Código seguro modificado:

$theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue);

Comportamiento del servidor Conectar usuario

Estos son los pasos para corregir el comportamiento del servidor de inicio de sesión de usuario:

Crear una función GetSQLValueString() como se describe en Conjunto de registros con un filtro anteriormente.

Modificar el código que construye la consulta SQL de inicio de sesión.



Código original:

$LoginRS__query=sprintf("SELECT username, password FROM login WHERE username='%s' AND password='%s'", get_magic_quotes_gpc() ? $loginUsername : addslashes($loginUsername), get_magic_quotes_gpc() ? $password : addslashes($password));

Código seguro modificado:

$LoginRS__query=sprintf("SELECT username, password FROM login WHERE username=%s AND password=%s", GetSQLValueString($loginUsername, "text"), GetSQLValueString($password, "text"));

Comportamiento del servidor Comprobar nuevo nombre de usuario

El comportamiento del servidor Comprobar nuevo nombre de usuario requiere añadir primero a la página un comportamiento del servidor Insertar registro. La función GetSQLValuesString() se incluye con el comportamiento del servidor Insertar registro. Todo lo que hay que hacer es actualizar GetSQLValuesString() para manejar mejor la inyección SQL y actualizar el comportamiento del servidor Comprobar nuevo usuario para usar esta función cuando se pase un parámetro.

Cambiar la primera línea de la función para actualizar la función GetSQLValuesString() como se describe en Actualizar la definición de la Variable $theValue.

Modificar el código para construir la consulta SQL de inicio de sesión para usar GetSQLValuesString() para pasar parámetros. Hacia la parte superior de la página, localizar el código en la sección que comienza con // *** Redirect if username exists.



Código original:

$LoginRS__query = "SELECT username FROM login WHERE username='" . $loginUsername . "'"



Código seguro modificado:

$LoginRS__query = sprintf("SELECT username FROM login WHERE username=%s", GetSQLValueString($loginUsername, "text"));

Juego de páginas Maestro-Detalle

En el caso del objeto de aplicación de juego de páginas Maestro-Detalle, los cambios se dan sobre todo en el juego de registros creado por Dreamweaver para la página de detalles. Si no tiene un juego de registros filtrados en la página maestra, no hace falta efectuar cambios en ella. Si tienes un conjunto de registros filtrado, consulta conjunto de registros con un filtro para actualizar el código del conjunto de registros.

Dreamweaver crea un conjunto de registros filtrado en la página de detalles, por lo que ese código del conjunto de registros debe actualizarse para usar una función GetSQLValueString() para pasar parámetros y sprintf() para construir la cadena SQL.

Crear la función GetSQLValueString() como se describe en Conjunto de registros con un filtro anteriormente.

Actualizar el código de declaración de Variable y construir la consulta SQL usando la función GetSQLValuesString().



Código original:

$recordID = $_GET['recordID']; $query_DetailRS1 = "SELECT * FROM albums WHERE ID = $recordID";



Código seguro modificado:

$colname_DetailRS1 = "-1"; if (isset($_GET['recordID'])) { $colname_DetailRS1 = (get_magic_quotes_gpc()) ? $_GET['recordID'] : addslashes($_GET['recordID']); } $query_DetailRS1 = sprintf("SELECT * FROM albums WHERE ID = %s", GetSQLValueString($colname_DetailRS1, "int"));

Asistente de formulario de actualización de registro

Actualizar el código del conjunto de registros necesario para el formulario de actualización de registro como se describe en paso 2 del conjunto de registros con un filtro.

Información adicional

Consulte el siguiente artículo para obtener más información sobre la inyección SQL: Artículo de Wikipedia sobre inyección SQL.

Boletín de seguridad de Adobe: APSB 06-07 Vulnerabilidad de inyección SQL del comportamiento del servidor de Dreamweaver.