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<?php
/**
*
* Seguridad GET con un hash MD5
*
* Comprueba en el script de destino que los datos de un query al que
* enlaza nuestra pagina son los originales
*
* Puede ser útil, por ejemplo, cuando queremos dar listas con
* soluciones a ejercicios a medida que avanza un curso. Con unos pares
* solucion / tema para que si una combinacion de número de solucion
* y tema no esta en lista de la pagina no pueda ser visto por el
* usuario utilizando la barra de direcciones o otreo sistema.
* También se puede cambiar la clave para cada usuario para
* identificar los que intentan saltarse la proteccion.
*
* Funciones de generacion:
* devuelveGetConHash
* @example lista.php
*
* Funcion de comprobacion:
* compruebaGetConHash
* @example resultadosprueba.php
*
* @author Miquel-Àngel Pintanel - imaginatic.com
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/
class CompruebaGetEntrePaginas
{
protected $palabraSecreta;
function __construct()
{
$this->palabraSecreta = $this->generaPalabraSecreta ();
if (!isset($_SESSION["intentoscrackeo"])){ $_SESSION["intentoscrackeo"] = 0;
}
}
/**
*
* Genera un GET con un codigo de comprobacion al final.
* Dependiendo del número de parámetros se devuelve un GET simple, una URL
* o un enlace completo
*
* @param array $ArrayVariables Array asociativo con los datos del GET
*
* @param null|string $NombreScript Si es una cadena vacia $_SERVER["PHP_SELF"]
*
* @param null|string $TextoEnlace Texto visible del enlace
*
* @return string
*/
public function devuelveGetConHash ($ArrayVariables,$NombreScript = NULL,$TextoEnlace = NULL)
{
return $this->GeneraGETconHash($ArrayVariables);
$elGETconHash = $this->GeneraGETconHash ($ArrayVariables);
$PrefijoURL = (empty($NombreScript))?
$_SERVER["PHP_SELF"] : $NombreScript; return $PrefijoURL.$elGETconHash;
} else {
echo "Archivo de script $NombreScript inexistente";
}
} else {
$laURL = $this->GeneraURL($ArrayVariables,$NombreScript);
return '<a href="'.$laURL.'">'.$TextoEnlace.'</a>';
}
}
/**
*
* Comprueba que no se ha modificado la URL
*
* @return bool
*/
public function compruebaGetConHash ()
{
$ArrayTrabajo = $_GET;
$ArrayTrabajo["palabraSecreta"] = $this->palabraSecreta;
$comparacionValores = ($ValorHash === $ValorEsperadoHash)? TRUE : FALSE;
return $comparacionValores;
}
/**
*
* Devuelve un error si hay un intento de cambiar el GET
*/
public function devuelveError ()
{
if (isset($_SESSION["intentoscrackeo"])){ $intentos = $_SESSION["intentoscrackeo"];
$intentos++;
$_SESSION["intentoscrackeo"] = $intentos;
if ($intentos < 5){
header("HTTP/1.1 404 Not found"); } else {
header('HTTP/1.1 500 Internal Server Error'); }
} else {
header("HTTP/1.1 404 Not found"); }
$this->registraError();
}
// Genera un GET con un codigo de comprobacion al final
protected function GeneraGETconHash ($ArrayVariables)
{
$GETconHash = "";
$Liga = "";
foreach ($ArrayVariables as $UnaLlave => $UnValor){
$GETconHash .= $Liga.$UnaLlave."=".$UnValor;
$Liga = "&";
}
$GETconHash = "?".$GETconHash;
$ArrayVariables["palabraSecreta"] = $this->palabraSecreta;
$GETconHash .= $Liga."ps=".$ClaveHash;
return $GETconHash;
}
// Genera una URL completa, simplemente sirve para que haya menos
// funciones en la creación de la lista
protected function GeneraURL ($ElArrayVariables,$NombreScript = "")
{
$elGETconHash = $this->GeneraGETconHash ($ElArrayVariables);
$PrefijoURL = (empty($NombreScript))?
$_SERVER["PHP_SELF"] : $NombreScript; $URLcompleta = $PrefijoURL.$elGETconHash;
return $URLcompleta;
}
// Genera un enlace completo
protected function GeneraEnlace ($ElArrayVariables,$TextoEnlace,$NombreScript = ""){
$laURL = $this->GeneraURL($ElArrayVariables,$NombreScript);
return '<a href="'.$laURL.'">'.$TextoEnlace.'</a>';
}
/**
*
* Reescribir esta función si se quiere registrar los intentos de modificación
*/
protected function registraError ()
{
return TRUE;
}
/**
*
* Para mas seguridad se deberia reescribir esta funcion para leer el valor de una base de datos
*/
protected function generaPalabraSecreta ()
{
// Este valor de retorno debe cambiarse para mas seguridad
return 'flghusf';
}
}
lista.php
Código PHP:
Ver original<?php
include_once ("seguridadpareshashsimple.php");
// Iniciamos la clase de creacion/comprobacion
$CreaCompruebaURL = new CompruebaGetEntrePaginas ();
// En esta variable ponemos el nombre del script PHP. Si esta vacio
// o no esta definido se usa $_SERVER["PHP_SELF"]
$NombreScriptDestino = "resultadosprueba.php";
// Datos que iran en el GET y en el texto del enlace
$DatosGet = Array("solucion" => "12","tema" => "25"); $TextoEnlace = "Resultados al ejercicio 12 del tema 25";
// Mostramos el resultado en pantalla
print ("<h1>Pruebas salida</h1>");
print ("<h2>Solo GET</h2>");
print ($CreaCompruebaURL->devuelveGetConHash ($DatosGet));
print ("<h2>Solo URL</h2>");
print ($CreaCompruebaURL->devuelveGetConHash ($DatosGet,$NombreScriptDestino));
print "<h2>Completo</h2>";
print ($CreaCompruebaURL->devuelveGetConHash ($DatosGet,$NombreScriptDestino,$TextoEnlace));
resultadosprueba.php
Código PHP:
Ver original<?php
include_once ("seguridadpareshashsimple.php");
$CreaCompruebaURL = new CompruebaGetEntrePaginas ();
// Comprobamos que coincide el contenido de las variables de GET con el hash MD5 final
if ($CreaCompruebaURL->compruebaGetConHash () === FALSE){
$CreaCompruebaURL->devuelveError();
} else {
// Aquí iría el código que muestra los datos si la comprobacion es correcta.
// En este ejemplo solo mostramos que todo ha ido bien
echo "Datos URL originales<br/>";
}