Documentos de Académico
Documentos de Profesional
Documentos de Cultura
22 y 27 de Septiembre de 2004
Seguridad en PHP
Lineamientos Generales. Filtrado de la Entrada. Utilizacin de Libreras. Diseo en Tres Capas.
Gabriel Arellano
arellanog@frcu.utn.edu.ar
Introduccin
PHP es un lenguaje que en casi todos los casos estar soportando aplicaciones accesibles va Internet. Por esto se deben tener en cuenta aspectos de seguridad que normalmente se pasaran por alto en el caso de lenguajes de programacin tradicionales.
Register Globals
La directiva register_globals permite que las variables pasadas por el cliente se registren como variables globales en nuestras aplicaciones. Esta directiva est desabilitada por defecto desde la versin 4.1.0 de PHP.
En principio: Considere los usos ilegtimos de su aplicacin. Filtre la informacin proveniente del exterior. Investigue constantemente. Esta directiva en s no es una vulnerabilidad, pero representa un riesgo de seguridad. Por lo tanto debera disear sus aplicaciones para que funcionen sin register_globals activada.
Register Globals
Tomemos este ejemplo:
<?php include "$path/common.php"; ?>
Register Globals
Recomendaciones: Inicializar todas la variables antes de utilizarlas.
Establecer error_reporting a E_ALL durante el desarrollo. Siempre tomar los valores de los arreglos _POST y _GET. Evitar trabajar con register_globals activado.
Mi script quedara:
Filtrado de la Entrada
Como afirmamos varias veces, el filtrado de la informacin que el cliente enva es la pieza fundamental de la seguridad web. Esto involucra establecer mecanismos mediante los cuales se pueda determinar la validez de los datos que estn siendo enviados. Un buen diseo debe ayudar a los desarrolladores a: Asegurar que el filtrado de datos no pueda evitarse. Asegurar que informacin invlida no pueda ser confundida con informacin vlida. Identificar el origen de los datos.
Filtrado de la Entrada
Para lograr los objetivos planteados anteriormente se pueden considerar dos enfoques: El enfoque dispatch (despachador). Un nico script es el que est disponible va web. Todo lo dems son mdulos que se invocan a travs de llamadas include o require. El enfoque include. Contamos con un nico mdulo encargado de las funciones de seguridad. Este mdulo es includo al principio de todos nuestros scripts que estn disponibles va web.
El enfoque dispatch
Este mtodo normalmente requiere que se pase una variable con la operacin a realizar (En lugar de llamar a un script en particular). Por ejemplo:
http://www.compras.com/main.php?accion=imprimir
El enfoque dispatch
<?php /* Medidas de seguridad */ switch ($_GET['accion']){ case 'imprimir': include '/inc/presentation/form.inc'; break; case 'procesar': $form_valid = false; include '/inc/logic/process.inc'; if ($form_valid) { include '/inc/presentation/end.inc'; } else { include '/inc/presentation/form.inc'; } break; default: include '/inc/presentation/index.inc'; break; } ?>
El script main.php es el nico disponible va web. Esto permite al desarrollador: Implementar medidas de seguridad en el script main.php y asegurarse que esas medidas no puedan ser evitadas. Fcilmente verificar que el filtrado de datos es llevado a cabo ya que todos los datos pasan por el script main.php.
El enfoque include
El enfoque include es el de tener unnico mdulo encargado de las funciones de seguridad. Este mdulo es incluido al principio de todos los scripts. Por ejemplo:
<?php switch ($_POST['formulario']){ case 'login': $permitido = array(); $permitido[] = 'formulario'; $permitido[] = 'usuario'; $permitido[] = 'contrasenia'; $enviado = array_keys($_POST); if ($permitido == $enviado){ include '/inc/logic/procesar.inc'; } break; } ?>
Filtrado de la Entrada
En cuanto a los datos recibidos desde el cliente es importante tomar un enfoque de lo que no est explcitamente definido no se considera vlido Por ejemplo, para recibir una direccin de correo:
<?php $validos = array(); $email_pattern='/^[^@\s]+@([-a-z0-9]+\.)+[a-z]{2,}$/i'; if (preg_match($email_pattern, $_POST['email'])){ $validas['email'] = $_POST['email']; } ?>
Este enfoque es difcil y hasta imposible de implementar cuando no sabemos el tipo de dato que vamos a manejar.
Filtrado de la Entrada
Tambin es recomendable implementar este enfoque cuando el nmero de opciones o valores aceptables son conocidos de antemano: Por ejemplo:
<?php $validos = array(); switch ($_POST['color']){ case 'rojo': case 'verde': case 'azul': $validos['color'] = $_POST['color']; break; } ?>
Filtrado de la Entrada
Es recomendable tambin asegurarse que los datos enviados sean del mismo tipo que el de la variable que los recibir: Por ejemplo:
<?php $validos = array(); if ($_POST['num1'] == strval(intval($_POST['num1']))){ $validos['num1'] = $_POST['num1']; } if ($_POST['num2'] == strval(floatval($_POST['num2']))){ $validos['num2'] = $_POST['num2']; } ?>
Cada vez que alguien visite la pgina todas sus cookies seran enviadas al script steal_cookies.php ubicado en un sitio distinto al nuestro... Para que este ataque sea efectivo hace falta que el navegador de la vctima tenga JavaScript activado.
Mi servidor no tiene manera de distinguir este pedido de un pedido hecho a mano por un usuario malicioso.
Para prevenir este tipo de ataques hay ciertas medidas que podemos tomar: Usar POST en lugar de GET. Usar _POST en lugar de confiarnos en register_globals. No pensar solamente en conveniencia. Forzar el uso de nuestros formularios.
Manejo de Sesiones
La seguridad de las sesiones es un tema complicado, por lo que no es de extraarse que sean el objetivo de muchos ataques. La mayora de los ataques a sesiones implican que el atacante intenta acceder a la sesin de otro usuario. La pieza crucial de informacin para un atacante es el identificador de sesin, ya que es lo nico que necesita el atacante para lograr su objetivo. Existen bsicamente tres mtodos empleados para obtener las credenciales de otro usuario: Prediccin. Captura. Fijacin.
Fijacin de Sesiones
Tomemos como ejemplo el siguiente script:
<?php session_start(); if (!isset($_SESSION['visitas'])){ $_SESSION['visitas'] = 1; } else{ $_SESSION['visitas']++; } echo $_SESSION['visitas']; ?>
Fijacin de Sesiones
Una solucin sera tratar de identificar la fuente de la sesin (el equipo del usuario que inicio la sesin).
<?php session_start(); if (isset($_SESSION['HTTP_USER_AGENT'])){ if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])){ /* Prompt for password */ exit; } } else { $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']); } ?>
Este es el tpico script de conexin que encontraremos en casi cualquier aplicacin en php que emplee bases de datos. Este script es llamado por cualquier otro que desee conectarse a la base de datos. Debemos asegurarnos que slo sea accesible a scripts autorizados.
SQL Injection
El usar bases de datos implica que nuestra aplicacin deber conectarse a las mismas y para ello deber emplear las credenciales correspondientes.
<?php $sql = "INSERT INTO users (reg_username, reg_password, reg_email) VALUES ('{$_POST['reg_username']}', '$reg_password', '{$_POST['reg_email']}')"; ?>
SQL Injection
Supongamos que un usuario malicioso escribe en su nombre de usuario:
bad_guy', 'mypass', ''), ('good_guy
Este script recibe los datos de un formulario donde el usuario escribe su nombre, contrasea y direccin de email.
SQL Injection
Lo podramos solucionar con la funcin especfica para mysql:
<?php $username = mysql_escape_string($_POST['reg_username']); $sql = "INSERT INTO users (reg_username, reg_password, reg_email) VALUES ('$username', '$reg_password', '{$_POST['reg_email']}')"; ?>
Recursos
Libros: Secure PHP Development Mohammed J. Kabir - Ed. Wiley Publishing. Recursos on-line: PHP Security Open Source Convention http://shiflett.org/talks/oscon2004/php-security Open Web Application Security Project http://www.owasp.org/ Cgisecurity http://www.cgisecurity.com