2012-09-22 42 views
7

Una empresa para la que estoy trabajando me pidió que tomara uno de sus sitios web y lo convirtiera en un subdominio de otro sitio web. Luego, me pidieron que extendiera el control de la sesión "conectado/desconectado" de su dominio principal a su subdominio.Controlador de regex de seguridad del sitio? (PHP)

Habiendo hecho esto, veo que hay problemas de control/administración. Debido a su gran cantidad de páginas individuales, y debido a su extensa estructura de directorios, es demasiado complicado para ellos agregar un fragmento de PHP a cada una de sus páginas para redireccionar en función del estado de sesión iniciada.

Aquí está mi solución ... por favor avísenme de cualquier problema o cualquier otra cosa que me ayude.

  1. voy a utilizar Mod_rewrite para redirigir todas las peticiones en el subdomin a una página específica (handler.php? Requested_url =).
  2. Voy a hacer una sección de "El sitio permite/prohíbe las reglas" en su sitio web. Esta sección contendrá un cuadro de texto con las reglas de la siguiente manera:

    +/weather/   ---> will allow anyone access to any url that contains "/weather/" somewhere within it, irregardless of logged-in status. 
    
    -/weather/premium/ ---> will only allow access to a url that contains /weather/premium to logged-in users. 
    

    Esta es la salida de una matriz almacenada en un archivo rules.php que se vería así:

    $ruleList = array(); 
    $ruleList[] = '+/weather/'; 
    $ruleList[] = '-/weather/premium/'; 
    
  3. En manejador .php, Si el usuario está conectado, los reenviaré al requested.url. Si el usuario no está conectado, entonces comenzaré suponiendo que cada página está restringida a usuarios que no han iniciado sesión. handler.php analizará el requested_url y compruébalo contra rules.php, para ver si hay algún permiso explícito establecido. Entonces, si la regla permite el acceso no registrado, enviará al usuario al requested_url, de lo contrario, lo enviará a la página de inicio de sesión.

Un problema que puedo ver de inmediato, es que dado que la regla Mod_rewrite enviará a cada petición handler.php, ¿cómo puedo evitar un bucle infinito?

¿La redirección debe hacerse por algún método que no sea header("Location: ")?

Editar: Aquí es una actualización de mi lucha:

Dentro de la .htaccess archivo del dominio superior (example.com) añadí:

#Prevent catching requests for the sub1 subdomain 
    RewriteCond %{REQUEST_URI} ^sub1\.example\.com 
    RewriteRule .* – [L] 

Entonces , dentro del .htaccess para el subdominio sub1.example.com, agregué lo siguiente:

IndexIgnore * 

    RewriteEngine On 
    RewriteBase /path/to/base 

    #Avoid infinite loop on outgoing requests 
    RewriteCond %{HTTP_REFERER} !^$ 
    RewriteCond %{REQUEST_URI} !^$ 
    RewriteCond %{HTTP_REFERER} !^/?handler.php?$ 
    RewriteCond %{REQUEST_URI} !^/?handler.php?$ 



     #Check for cookie. Redirect to handler if not found. (not yet implemented)        
     #RewriteCond %{HTTP_COOKIE} !session_id 
    RewriteRule (.*)$ handler.php?requested_url=$1 [NC,L,QSA] 

Aquí es manejador.php

<?php 

     $url = $_REQUEST['requested_url']; 

     //Check list of permissions. For now just assume permitted. 
     $permitted = true; 
     if ($url == "") $url = "http://sub1.example.com"; 
     if ($permitted) 
      header("Location: ".$url); 
     header("Location: http://sub1.example.com");   

    ?> 

estoy tan cerca que puedo saborearlo. Lamentablemente, por el momento estoy obteniendo un "bucle de redireccionamiento" en casi todas partes. Si alguien pudiera darme un empujón en la dirección correcta, ¡lo agradecería!

+0

también verifique esto http://www.ibm.com/developerworks/opensource/library/os-php-secure-apps/index.html –

+1

En cuanto a "agregar un fragmento a cada página demasiado involucrada", ¿lo hizo? considere [auto_prepend_file] (http://php.net/manual/en/ini.core.php#ini.auto-prepend-file)? – Leigh

+0

Bueno, por lo que entiendo su configuración, solo debería obtener infinitos bucles de redirección si la página de inicio de sesión está clasificada como acceso restringido, ¿verdad? Entonces, ¿tu parte de análisis de reglas y URL hace algo inesperado? –

Respuesta

2

Creo que hay un bucle en su idea, de ahí el ciclo en la aplicación. De esta manera:

  1. User-agent solicita un recurso heredado en el subdominio.

  2. Como UA debe tener credenciales válidas y el recurso heredado no puede verificar las credenciales, UA se redirige al controlador.

  3. El manejador verifica las credenciales y redirige a UA al recurso heredado.

  4. Ir a 2.

El problema es que el recurso solicitado no se puede hacer una distinción entre las peticiones de la UA en los pasos 1 y 3, debido a que la distinción se define por las credenciales de la UA, que el legado recurso no evalúa.

Esta contradicción también es evidente desde otro punto de vista. Imagine por un minuto que resuelve el ciclo y el UA se redirige al recurso heredado, algo así como http://sub1.example.com/foo.php. Para que el servidor devuelva el recurso, debería significar que las credenciales no se evaluaron (porque no lo hace) y, por lo tanto, que el recurso es efectivamente público.

Para evitar esto, usted tiene que romper el punto muerto al cambiar las reglas de cualquiera de los pasos 2 o 3:

  • para cambiar el paso 2, agregue evaluación de credenciales a la respuesta para el recurso legado. La respuesta anterior que sugiere auto_prepend_file() va en esa dirección, pero solo para los archivos heredados de PHP: imágenes, HTML, etc. no tienen suerte.

  • para cambiar el paso 3, encuentre una forma de entregar el recurso heredado sin que la UA solicite el recurso directamente. Una posibilidad es hacer que el controlador obtenga el recurso del sistema de archivos y ponerlo en el cable con readfile() y alguna gestión de encabezado HTTP.

Tal vez una combinación de éstos va a hacer el truco para usted: auto_prepend_file() a requerir una manipulación a PHP legado autenticación y readfile() de contenido que no sea PHP.

2

¿Hay algún motivo por el que no desee utilizar apache auth? Creo que sería mucho menos complicado. http://httpd.apache.org/docs/2.2/howto/auth.html

Puede especificar reglas de acceso en un host virtual directorio por directorio, su información de usuario puede estar en un archivo sin formato o base de datos.

+0

Probablemente la razón sea la falta de experiencia ;-) Echaré un vistazo a esto, gracias –

+0

Después de analizar esto, el problema es que estas reglas de acceso a directorios deben cambiar dinámicamente en función de la entrada a través de un panel de administración. –

+0

Hola Mike; ¿con qué frecuencia cambian? Puede regenerar su configuración de apache dinámicamente (y reiniciar Apache) cuando sea necesario. –

3

Solo una idea, pero tal vez no necesite luchar con mod_rewrite. Si desea manejar todo desde PHP de todos modos, ¿por qué no agregar un archivo de antepecho a su VHOST?

php_value auto_prepend_file handler.php 

Se incluirá antes de cualquier script de PHP y puede redirigir si es necesario.

+0

Creo que esta solución tiene mucho sentido. Su pregunta propuso una solución realmente complicada y esta es muy simple. – MikeMurko

1

Solo necesita una función de verificación simple. Un usuario puede acceder a un recurso o no. Así que en primer lugar la configuración del contexto:

$rules   = rules_load(); 
$uri   = $_SERVER['QUERY_STRING']; 
$userIsLoggedIn = user_is_logged_in(); 

Además tenemos la dicha función validación que por defecto debe devolver false y toma el contexto como parámetros:

$validation = function (array $rules, $uri, $userIsLoggedIn) { 
    $permitted = false;  
    return $permitted; 
}; 

La lógica entonces es sencillo :

if ($validation($rules, $uri, $userIsLoggedIn)) { 
    # can pass 
    echo "can pass"; 
} else { 
    # login first 
    echo "login first"; 
} 

que, naturalmente, ya que da "login primero". Multa. Cambiaremos los parámetros de esa función pronto. Veamos cómo se comparan el $rules y el $uri.

Cada regla puede coincidir en un URI, al menos ruta puede. Vamos a dividir la regla:

<sign><path> 

sign := [+-] 
path := <segment>*/ 
segment := /[a-z]+ 

Una regla hace o no coincide con el $uri. Si coincide, el signo decide lo que significa.

De hecho, hay dos grupos especificados por el signo y se puede decir si el $uri coincide o no. De nuevo, esta es una función simple; primero, la matriz de reglas se filtra por signo y luego por ruta.

Considérese una función con tres parámetros de entrada que devuelve el subconjunto de todas las reglas en forma de una matriz que coincide con los URI:

function ($sign) use ($rules, $uri) { 
    return array_reduce($rules, function ($a, $v) use ($rules, $sign, $uri) { 
     $v[0] === $sign && false !== strpos($uri, substr($v, 1)) && $a[] = $v; 
     return $a; 
    }, array()); 
}; 

Esto es más o menos una llamada a array_reduce. Asumamos que esto estaría asociado a una variable llamada $match que luego puede reemplazar $rules y $uri como parámetro para la función $validation.

$validation = function ($match, $userIsLoggedIn) { 

Así que la parte sobrante es simplemente formular las condiciones de validación ahora:

$permitted = $userIsLoggedIn; 

Por defecto, si el usuario ha iniciado sesión, se concede el permiso. Solo si el usuario no está conectado, podemos otorgar el permiso si el grupo no coincide y el grupo + coincide. El - El grupo debe ser lo primero y anular cualquier regla + por razones de seguridad:

$permitted = $userIsLoggedIn ?: !$match('-') && $match('+'); 

El resto es devolver la misma situación:

return $permitted; 
}; 

Como esta función es bastante trivial, podríamos emitirla. El código ahora completo:

$rules   = rules_load(); 
$uri   = $_SERVER['QUERY_STRING']; 
$userIsLoggedIn = user_is_logged_in(); 

$match = rules_match($rules, $uri); 

$permitted = $userIsLoggedIn ?: !$match('-') && $match('+'); 

if ($permitted) { 
    # can pass 
    echo "can pass"; 
} else { 
    # login first 
    echo "login first"; 
} 

/** 
*/ 
function rules_match(array $rules, $uri) { 
    return function ($sign) use ($rules, $uri) { 
     return array_reduce($rules, function ($a, $v) use ($rules, $sign, $uri) { 
      $v[0] === $sign && false !== strpos($uri, substr($v, 1)) && $a[] = $v; 
      return $a; 
     }, array()); 
    }; 
} 
+0

¿Y cuál es esta respuesta? Mike quiere saber sobre el bucle de redirección y usted reescribe su verificación de regla ??? – BigBoss

+0

@BigBoss: Lea la pregunta a fondo. Estos problemas son inexistentes en el momento en que pone su verificación de sesión allí. a menos que no lo ponga, siempre tendrá el problema de bucle. Como la implementación está oculta, no hay mucho que responder. Mike escribió que lo implementará. – hakre