miércoles, septiembre 28, 2005

Tips de seguridad en php

* Considera el uso ilegítimo de la aplicación
* Edúcate a ti mismo
* Desactiva register_globals
* Inicializar todas las variables usadas a valores nulos
* Filtra todos los datos externos
* Usando una página despachadora: Todo el acceso externo es a través de esta página
http://localhost/dispatch.php?tarea=login
http://localhost/app/login // si se usa la directiva ForceType o mode_rewrite
* Incluir las directivas de seguridad al principio de la página
* Validaciones
* Al enviar formas validar que no se envíen datos de mas (enviar un campo hidden que se llame form) Hacerlo tanto en post como en get
switch ($_POST['form']) {
case 'login':
$allowed = array();
$allowed[] = 'form';
$allowed[] = 'username';
$allowed[] = 'password';
$sent = array_keys($_POST);
if ($allowed == $sent) {
include '/inc/logic/process.inc';
}
break;
}
?>
* Validar cada uno de los datos que se envían al servidor, aceptar ciertos patrones nada más
* Manejar un arreglo con los datos que se van a usar y descartar todo lo que este fuera, agregar a este arreglo solo datos una vez validados
* Evitar que lleguen caracteres como ; " ' cuando se hacen consultas a la base de datos
* Permitir que php reporte todos los errores
* error_reporting = E_ALL
* display_errors = off
* log_errors = on
* error_log
* NOTA: si no se tiene acceso al archivo php.ini se pueden poner estas características con la función ini_set()
* hacer tus propios HTTP REQUEST (mas eficaz pero poco conveniente)
* XSS (cross-side scripting)
* Filtrar todos los datos externos
* Evitar que pongan código html o restringirlo a lo que se quiera nada mas
htmlentities(), strip_tags(), utf8_decode()
* Usar una lista de caracteres permitidos y validar que no se encuentren otros dentro de lo que se manda
* convención estricta de nombres
* Engaños Cross-Site Request
* Usar el método POST en vez de GET en las formas a menos que sea seguro usar get
* Usar $_POST para recibir los valores. Desactivar register_globals y no usar $_REQUEST
* Usar variables de control para validar si la página fue cargada desde el sitio y comprobarlo con las variables de sesión
$token = md5(uniqid(rand(), true));
$_SESSION['token'] = $token;
if (llegan las variables esperadas y son validas)
if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token'])
as lo que la página tiene que hacer
* Seguridad con bases de datos
* Credenciales
* No nombrar los archivos de conexión y configuración con extensión .inc solo usar php
* No poner los archivos de conexión y configuración carpetas que sean públicas
* Aceptan rutas del sistema de archivos
* include()
* requiere()
* En caso de no poder hacerlo modificar el httpd.conf

Order allow,deny
Deny from all

AddType inc
* La mejor es Tener una ruta secreta donde solo el root tenga acceso
SetEnv DB_USER "myuser"
SetEnv DB_PASS "mypass"
Añadir la ruta a httpd.conf
Include "/path/to/secret-stuff"
Usar:
$_SERVER['DB_USER']
$_SERVER['DB_PASS']
Nunca usar:
phpinfo()
print_r($_SERVER)
* sql
* Filtrar los datos
* usar siempre "'" alrededor de todos los valores sin importar el tipo
* usar siempre mysql_real_escape_string() o su similar
* Sessiones:
* Aparte de usar session_start() debemos de considerar enviar cada vez
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']);
}
?>
* involucrar mas headers
* Manejar las sesiones desde la base de datos
* Sistema de archivos
* activar safe_mode
* usar open_basedir
* Encriptar todo el tráfico, una o dos vías, segün sea necesario (crypt() una vía)
* Encriptar cookies por lo menos usar:
setcookie(base64_encode($cookie));

Falta un poco de código en esta parte, si requieren leer todo el artículo busquenlo en los documentos de PHPSecurity.

Fuente principal: PHPSecurity Consortium
link: http://phpsec.org/library/