Ver Mensaje Individual
  #2 (permalink)  
Antiguo 16/01/2012, 05:59
pintix
 
Fecha de Ingreso: octubre-2004
Ubicación: Barcelona
Mensajes: 195
Antigüedad: 20 años, 1 mes
Puntos: 7
Respuesta: [Aporte] Clase para comprobar datos de un GET entre páginas

He hecho una versión bastante más depurada. Ahora funciona con una sola función para generar los datos y sólo hace falta añadir parámetros a la función para que haga más compleja la salida.

También he desarrollado la devolución del error, en este caso envía un Error 404 al navegador después de unos segundos de espera. He dejado una parte de la función que aumenta la espera a medida que se intenta saltar la protección y cambia el error devuelto a 500 aunque no sé si será de mucha utilidad ya que funciona con sesiones. La idea inicial era "luchar" contra alguna herramienta automatizada pero, aunque no soy un hacker y lo desconozco, supongo que estas herramientas deben "pasar" de las sesiones.

Por el camino he visto que Firefox (al menos Firefox 9) ya no deja cambiar los datos de un GET en la barra del navegador. Aunque sí permite copiar, pegar y modificar el enlace en otra ventana es un buen avance en seguridad.

seguridadpareshashsimple.php
Código PHP:
Ver original
  1. <?php
  2. /**
  3.  *
  4.  * Seguridad GET con un hash MD5
  5.  * 
  6.  * Comprueba en el script de destino que los datos de un query al que
  7.  * enlaza nuestra pagina son los originales
  8.  * 
  9.  * Puede ser útil, por ejemplo, cuando queremos dar listas con
  10.  * soluciones a ejercicios a medida que avanza un curso. Con unos pares
  11.  * solucion / tema para que si una combinacion de número de solucion
  12.  * y tema no esta en lista de la pagina no pueda ser visto por el
  13.  * usuario utilizando la barra de direcciones o otreo sistema.
  14.  * También se puede cambiar la clave para cada usuario para
  15.  * identificar los que intentan saltarse la proteccion.
  16.  *
  17.  * Funciones de generacion:
  18.  *  devuelveGetConHash
  19.  * @example lista.php
  20.  *
  21.  * Funcion de comprobacion:
  22.  *  compruebaGetConHash
  23.  * @example resultadosprueba.php
  24.  *
  25.  * @author Miquel-Àngel Pintanel - imaginatic.com
  26.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  27. */
  28. class CompruebaGetEntrePaginas
  29. {  
  30.     protected $palabraSecreta;
  31.    
  32.     function __construct()
  33.     {
  34.         $this->palabraSecreta = $this->generaPalabraSecreta ();
  35.         if (!isset($_SESSION["intentoscrackeo"])){
  36.             $_SESSION["intentoscrackeo"] = 0;
  37.         }
  38.     }
  39.    
  40.     /**
  41.      *
  42.      * Genera un GET con un codigo de comprobacion al final.
  43.      * Dependiendo del número de parámetros se devuelve un GET simple, una URL
  44.      * o un enlace completo
  45.      *
  46.      * @param array $ArrayVariables Array asociativo con los datos del GET
  47.      *
  48.      * @param null|string $NombreScript Si es una cadena vacia $_SERVER["PHP_SELF"]
  49.      *
  50.      * @param null|string $TextoEnlace Texto visible del enlace
  51.      *
  52.      * @return string
  53.      */
  54.     public function devuelveGetConHash ($ArrayVariables,$NombreScript = NULL,$TextoEnlace = NULL)
  55.     {
  56.         if (is_null($NombreScript) && is_null($TextoEnlace)){
  57.             return $this->GeneraGETconHash($ArrayVariables);
  58.         } elseif (is_null($TextoEnlace)){
  59.             $elGETconHash = $this->GeneraGETconHash ($ArrayVariables);
  60.             $PrefijoURL = (empty($NombreScript))? $_SERVER["PHP_SELF"] : $NombreScript;
  61.             if (file_exists($NombreScript)){
  62.                 return $PrefijoURL.$elGETconHash;
  63.             } else {
  64.                 echo "Archivo de script $NombreScript inexistente";
  65.                 exit ();
  66.             }
  67.         } else {
  68.             $laURL = $this->GeneraURL($ArrayVariables,$NombreScript);
  69.             return '<a href="'.$laURL.'">'.$TextoEnlace.'</a>';
  70.         }
  71.     }
  72.  
  73.     /**
  74.      *
  75.      * Comprueba que no se ha modificado la URL
  76.      *
  77.      * @return bool
  78.      */
  79.     public function compruebaGetConHash ()
  80.     {
  81.         $ArrayTrabajo = $_GET;
  82.         $ValorHash = array_pop ($ArrayTrabajo);
  83.         $ArrayTrabajo["palabraSecreta"] = $this->palabraSecreta;
  84.         $ValorEsperadoHash = hash ("md5",serialize($ArrayTrabajo));
  85.         $comparacionValores = ($ValorHash === $ValorEsperadoHash)? TRUE : FALSE;
  86.         return $comparacionValores;
  87.     }
  88.    
  89.     /**
  90.      *
  91.      * Devuelve un error si hay un intento de cambiar el GET
  92.      */
  93.     public function devuelveError ()
  94.     {
  95.         if (isset($_SESSION["intentoscrackeo"])){
  96.             $intentos = $_SESSION["intentoscrackeo"];
  97.             $intentos++;
  98.             $_SESSION["intentoscrackeo"] = $intentos;
  99.             sleep(5 * $intentos);
  100.             if ($intentos < 5){
  101.                  header("HTTP/1.1 404 Not found");
  102.             } else {
  103.                 header('HTTP/1.1 500 Internal Server Error');
  104.             }
  105.         } else {
  106.             sleep(15);
  107.             header("HTTP/1.1 404 Not found");
  108.         }
  109.         $this->registraError();
  110.     }
  111.    
  112.     // Genera un GET con un codigo de comprobacion al final
  113.     protected function GeneraGETconHash ($ArrayVariables)
  114.     {
  115.         $GETconHash = "";
  116.         $Liga = "";
  117.         foreach ($ArrayVariables as $UnaLlave => $UnValor){
  118.             $GETconHash .= $Liga.$UnaLlave."=".$UnValor;
  119.             $Liga = "&";
  120.         }
  121.         $GETconHash = "?".$GETconHash;
  122.         $ArrayVariables["palabraSecreta"] = $this->palabraSecreta;
  123.         $ClaveHash = hash ("md5",serialize($ArrayVariables));
  124.         $GETconHash .= $Liga."ps=".$ClaveHash;
  125.         return $GETconHash;
  126.     }
  127.    
  128.     // Genera una URL completa, simplemente sirve para que haya menos
  129.     // funciones en la creación de la lista
  130.     protected function GeneraURL ($ElArrayVariables,$NombreScript = "")
  131.     {      
  132.         $elGETconHash = $this->GeneraGETconHash ($ElArrayVariables);
  133.         $PrefijoURL = (empty($NombreScript))? $_SERVER["PHP_SELF"] : $NombreScript;
  134.         $URLcompleta = $PrefijoURL.$elGETconHash;
  135.         return $URLcompleta;
  136.     }
  137.    
  138.     // Genera un enlace completo
  139.     protected function GeneraEnlace ($ElArrayVariables,$TextoEnlace,$NombreScript = ""){
  140.         $laURL = $this->GeneraURL($ElArrayVariables,$NombreScript);
  141.         return '<a href="'.$laURL.'">'.$TextoEnlace.'</a>';
  142.     }
  143.     /**
  144.      *
  145.      * Reescribir esta función si se quiere registrar los intentos de modificación
  146.      */
  147.     protected function registraError ()
  148.     {
  149.         return TRUE;
  150.     }
  151.    
  152.     /**
  153.      *
  154.      * Para mas seguridad se deberia reescribir esta funcion para leer el valor de una base de datos
  155.      */
  156.     protected function generaPalabraSecreta ()
  157.     {
  158.         // Este valor de retorno debe cambiarse para mas seguridad
  159.         return 'flghusf';
  160.     }
  161. }

lista.php
Código PHP:
Ver original
  1. <?php
  2. include_once ("seguridadpareshashsimple.php");
  3.  
  4. // Iniciamos la clase de creacion/comprobacion
  5. $CreaCompruebaURL = new CompruebaGetEntrePaginas ();
  6.  
  7. // En esta variable ponemos el nombre del script PHP. Si esta vacio
  8. // o no esta definido se usa $_SERVER["PHP_SELF"]
  9. $NombreScriptDestino = "resultadosprueba.php";
  10.  
  11. // Datos que iran en el GET y en el texto del enlace
  12. $DatosGet = Array("solucion" => "12","tema" => "25");
  13. $TextoEnlace = "Resultados al ejercicio 12 del tema 25";
  14.  
  15. // Mostramos el resultado en pantalla
  16. print ("<h1>Pruebas salida</h1>");
  17. print ("<h2>Solo GET</h2>");
  18. print ($CreaCompruebaURL->devuelveGetConHash ($DatosGet));
  19. print ("<h2>Solo URL</h2>");
  20. print ($CreaCompruebaURL->devuelveGetConHash ($DatosGet,$NombreScriptDestino));
  21. print "<h2>Completo</h2>";
  22. print ($CreaCompruebaURL->devuelveGetConHash ($DatosGet,$NombreScriptDestino,$TextoEnlace));

resultadosprueba.php
Código PHP:
Ver original
  1. <?php
  2. include_once ("seguridadpareshashsimple.php");
  3. $CreaCompruebaURL = new CompruebaGetEntrePaginas ();
  4.  
  5. // Comprobamos que coincide el contenido de las variables de GET con el hash MD5 final
  6. if ($CreaCompruebaURL->compruebaGetConHash () === FALSE){
  7.     $CreaCompruebaURL->devuelveError();
  8. } else {
  9.     // Aquí iría el código que muestra los datos si la comprobacion es correcta.
  10.     // En este ejemplo solo mostramos que todo ha ido bien
  11.     echo "Datos URL originales<br/>";
  12. }