2010-09-01

Clase PHP para filtrar los parámetros recibidos por GET

A raiz de la publicación del post The Perishable Press 4G Blacklist me surgió la idea de publicar una de las clases en PHP que utilizo para controlar la seguridad de los sitios web desarrollados en este lenguaje. Toda prevención es poca y hay veces que no tenemos acceso al fichero .htaccess, no conocemos lo suficiente su funcionamiento, el servidor no es Apache, etc. En ese caso utilizar una clase como la siguiente nos puede ser útil para evitar ataques CSRF o XSS mediante parámetros GET.
  1. class dXSS{  
  2.     var $url;  
  3.     var $longitud;  
  4.   
  5. function TestGet(){  
  6.     $ok = true;  
  7.     $baneados =array(chr(34),  
  8.     "'",  
  9.     "--",  
  10.     ";"  
  11.     "<",  
  12.     "[",  
  13.     "&lt;",  
  14.     ">",  
  15.     "&gt",  
  16.     "&quot",  
  17.     "&#x27",  
  18.     "%",  
  19.     "&#x2F",  
  20.     "/*",  
  21.     "*/",  
  22.     "request",  
  23.     "select",  
  24.     "declare",  
  25.     "insert",  
  26.     "update",  
  27.     "delete",  
  28.     "drop",  
  29.     "exec(",  
  30.     "execute(",  
  31.     "cast(",  
  32.     "char",  
  33.     "nchar",  
  34.     "varchar",  
  35.     "nvarchar",   
  36.     "substring",  
  37.     "sysobject",  
  38.     "iframe",  
  39.     "syscolumns"  
  40.     );  
  41.       
  42.     $recuento=0;  
  43.     foreach( $_GET as $key => $value ) {  
  44.         for($i=0;$i<sizeof($baneados);$i++) {  
  45.             $Cadena = strtoupper($value);  
  46.             $Encontrar   = strtoupper($baneados[$i]);  
  47.             $pos = strpos($Cadena, $Encontrar);  
  48.             if($pos !== false) {  
  49.                 $recuento++;  
  50.             }  
  51.             if(strlen($Cadena)>$this->longitud){  
  52.                 $recuento++;  
  53.             }  
  54.             if(eregi('[^a-z0-9_]',$Cadena)){  
  55.                 $recuento++;  
  56.             }     
  57.         }  
  58.     }  
  59.         if($recuento>0){  
  60.              header('Location:'.$this->url);  
  61.         }  
  62.     }  
  63. }  
La clase testea cada uno de los parámetros recibidos y:
1.- Se asegura que no esté en la lista de palabras baneadas
2.- Se asegura de que no tenga una longitud superior a la especificada
3.- Comprueba que sólo contenga caracteres alfanuméricos
Si se detecta un parámetro no válido se redirige a la $url especificada.
Un ejemplo de funcionamiento sería:
  1. $g = new dXSS();  
  2. $g->url = 'http://www.google.es';  
  3. $g->longitud = 10;  
  4. $g->TestGet();  
Este código debe ir antes de que se haya producido cualquier salida desde el navegador. Al principio de la página por ejemplo.
De este modo se aceptarían parámetros como:
  1. http://www.dominio.com/index.php?Id=45&acc=new&op=32  
Pero no aceptaría cosas como:
  1. http://www.dominio.com/index.php?p=<script>alert("XSS");</script>  
Es bastante interesante definir una longitud pequeña, siempre que sea posible:
  1. $g = new dXSS();  
  2. $g->url = 'http://www.google.es';  
  3. $g->longitud = 3;  
  4. $g->TestGet();  
Permitiría:
  1. http://www.dominio.com/index.php?Id=45&sub=3&acc=new&op=32  
Pero no:
  1. http://www.dominio.com/index.php?Id=<meta%20http-equiv="refresh"%20content="0;">  
o incluso:
  1. http://www.dominio.com/index.php?Id=$%  
NOTA: Esta clase únicamente controla los parámetros recibidos por $_GET. Fácilmente se podría adaptar o modificar la clase para la información recibida por $_POST o que incluso se ocupase de ambas cosas pero quería mostrar un uso muy sencillo. Lo ideal es combinar esta clase con otras clases o funciones que comprueben el contenido recibido a través de los formularios, utilizar tokens en los formularios, establecer los permisos apropiados a las carpetas del sitio web, utilizar .htaccess, recurrir a filter_input si la versión de PHP instalada es reciente, etc. En estas cosas más vale que sobre que falte.

No hay comentarios: