Abuso de incluir
1. Causa de la vulnerabilidad:
Incluir es la función más utilizada al escribir sitios web PHP y admite rutas relativas. Hay muchos scripts PHP que utilizan directamente una variable de entrada como parámetro de inclusión, lo que provoca vulnerabilidades como referencias de script arbitrarias y fugas de ruta absolutas. Mira el siguiente código:
...
$includepage=$_GET["includepage"];
incluir ($ incluir página);
...
Obviamente, solo necesitamos enviar diferentes variables de Includepage para obtener la página deseada. Si envía una página que no existe, puede provocar un error en el script PHP y filtrar la ruta absoluta real (la solución a este problema se explica en el siguiente artículo).
2. Resolución de vulnerabilidad:
La solución a esta vulnerabilidad es muy sencilla, que consiste en determinar primero si la página existe y luego incluirla. O más estrictamente, use una matriz para especificar los archivos que se pueden incluir. Mira el siguiente código:
$pagelist=array("test1.php","test2.php","test3.php"); //Esto especifica los archivos que se pueden incluir
if(isset($_GET["includepage"])) //Determina si existe $includepage
{
$includepage=$_GET["includepage"];
foreach ($ lista de páginas como $ prepágina)
{
if($includepage==$prepage) //Comprueba si el archivo está en la lista permitida
{
incluir($prepagina);
$checkfind=verdadero;
romper;
}
}
if($checkfind==true){ unset($checkfind }
else{ die("¡Página de referencia no válida!");
}
Esto solucionará muy bien el problema.
Consejo: Las funciones con este problema incluyen: require(), require_once(), include_once(), readfile(), etc. También debes prestar atención al escribir.
Las variables de entrada no se filtran
1. Causa de la vulnerabilidad:
Esta vulnerabilidad apareció hace mucho tiempo en ASP, lo que provocó innumerables vulnerabilidades de inyección en ese momento. Pero debido a que PHP tenía una pequeña influencia en ese momento, no mucha gente podía prestarle atención. Para PHP, el impacto de esta vulnerabilidad es mayor que el de ASP, porque más scripts PHP utilizan bases de datos de texto. Por supuesto, también existe el problema de la inyección de declaraciones SQL. Para dar un ejemplo más clásico, el primero es la base de datos:
$id=$_GET["id"];
$query="SELECT * FROM my_table donde id='".$id."'" //Una vulnerabilidad de inyección SQL muy clásica
$resultado=mysql_query($consulta);
Aquí es obvio que podemos usar la inyección para obtener otros contenidos de la base de datos. No lo describiré en detalle aquí. Al igual que la inyección ASP, puedes echar un vistazo a las defensas negras anteriores. Luego miramos el problema de las bases de datos de texto:
$texto1=$_POST["texto1"];
$texto2=$_POST["texto2"];
$texto3=$_POST["texto3"];
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
Podría decirse que la vulnerabilidad del texto es aún más grave. Si insertamos una pequeña porción de código PHP en la variable enviada, podemos convertir esta base de datos de texto test.php en una puerta trasera PHP. Incluso insertar el código de carga nos permite cargar una puerta trasera PHP completa. Luego aumenta los privilegios y el servidor será tuyo.
2. Resolución de vulnerabilidad:
La solución a esta vulnerabilidad es realmente muy simple: filtrar estrictamente todas las variables enviadas. Reemplace algunos caracteres sensibles. Podemos reemplazar el contenido de HTML con la ayuda de la función htmlspecialchars() proporcionada por PHP. Aquí hay un ejemplo:
//Construir función de filtro www.knowsky.com
función flt_tags($texto)
{
$badwords=array("Vete a la mierda","joder"); //Lista de filtros de palabras
$texto=rtrim($texto);
foreach($badwords as $badword) //Filtrar vocabulario aquí
{
if(stristr($text,$badword)==true){ die("Error: el contenido que envió contiene palabras confidenciales, no envíe contenido confidencial.");
}
$text=htmlspecialchars($texto); //Reemplazo de HTML
//Estas dos líneas reemplazan el retorno de carro con
$text=str_replace("r","
",$texto);
$texto=str_replace("n","",$texto);
$text=str_replace("&line;","│",$text); //Reemplaza el separador de texto de la base de datos "&line;" con el ancho completo "│"
$text=preg_replace("/s{ 2 }/"," ",$texto //reemplazo de espacio);
$text=preg_replace("/t/"," ",$text // Aún reemplazando espacios);
if(get_magic_quotes_gpc()){ $text=stripslashes($text } //Si magic_quotes está activado, reemplaza '
devolver $texto;
}
$texto1=$_POST["texto1"];
$texto2=$_POST["texto2"];
$text3=$_POST["text3"]
//Filtrar todas las entradas
$texto1=flt_tags($texto1);
$texto2=flt_tags($texto2);
$text3=flt_tags($text3);
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
Después de algunos reemplazos y filtrados, puede escribir los datos de forma segura en texto o en una base de datos.
El juicio del administrador es incompleto.
1. Causa de la vulnerabilidad:
Usamos PHP para escribir scripts, que generalmente implican permisos de administrador. Algunas secuencias de comandos sólo emiten un juicio "sí" sobre los permisos de administrador, pero a menudo ignoran el juicio "no". Cuando Register_globals está activado en el archivo de configuración de PHP (está desactivado de forma predeterminada en las versiones posteriores a 4.2.0, pero muchas personas lo activan por conveniencia, lo cual es un comportamiento extremadamente peligroso), habrá situaciones en las que se enviarán variables para suplantar administradores. Echemos un vistazo al código de ejemplo:
$cookiesign="admincookiesign"; //Determinar si la variable de cookie del administrador
$adminsign=$_COOKIE["sign"] //Obtiene la variable de cookie del usuario
if($adminsign==$cookiesign)
{
$admin=verdadero;
}
if($admin){ echo "Ahora eres administrador.";
Parece muy seguro, jaja. Ahora asumimos que Register_globals está activado en el archivo de configuración de PHP. Enviamos dicha dirección "test.php?admin=true", ¿has visto el resultado? Aunque no tenemos la cookie correcta, debido a que Register_globals está activado, la variable de administración que enviamos se registra automáticamente como verdadera. Además, el script carece de un juicio "no", lo que nos permite obtener permisos de administrador con éxito a través de admin=true. Este problema existe en la mayoría de los sitios web y foros.
2. Resolución de vulnerabilidad:
Para resolver este problema, solo necesitamos agregar un juicio "no" al administrador en el script. Todavía asumimos que Register_globals está activado en el archivo de configuración de PHP. Echa un vistazo al código:
$cookiesign="admincookiesign"; //Determinar si la variable de cookie del administrador
$adminsign=$_COOKIE["sign"] //Obtiene la variable de cookie del usuario
if($adminsign==$cookiesign)
{
$admin=verdadero;
}
demás
{
$admin=falso;
}
if($admin){ echo "Ahora eres administrador.";
De esta manera, incluso si el atacante envía la variable admin=true sin la cookie correcta, el script establecerá $admin en False en futuros juicios. Esto resuelve parte del problema. Sin embargo, dado que $admin es una variable, si se produce una laguna en otras referencias de script en el futuro y se reasigna $admin, se producirá una nueva crisis. Por lo tanto, deberíamos utilizar constantes para almacenar la determinación de los permisos de administrador. Utilice la instrucción Define() para definir una constante de administrador para registrar los permisos de administrador. Si se reasigna después de esto, se producirá un error, logrando el propósito de protección. Mira el siguiente código:
$cookiesign="admincookiesign"; //Determinar si la variable de cookie del administrador
$adminsign=$_COOKIE["sign"] //Obtiene la variable de cookie del usuario
if($adminsign==$cookiesign)
{
definir (administrador, verdadero);
}
demás
{
definir (administrador, falso);
}
if(admin){ echo "Ahora estás en estado de administrador.";
Vale la pena señalar que usamos la declaración Define, por lo que cuando llame a la constante Admin, no agregue habitualmente el símbolo de variable $ al frente, sino que use Admin y! Admin.
Base de datos de texto expuesta
1. Causa de la vulnerabilidad:
Como se mencionó anteriormente, debido a la gran flexibilidad de las bases de datos de texto, no se requiere soporte externo. Además, PHP tiene capacidades de procesamiento de archivos muy sólidas, por lo que las bases de datos de texto se utilizan ampliamente en los scripts PHP. Incluso existen varios buenos programas de foros que utilizan bases de datos de texto. Pero hay ganancias y pérdidas, y la seguridad de las bases de datos de texto es menor que la de otras bases de datos.
2. Resolución de vulnerabilidad:
La base de datos de texto actúa como un archivo normal, que se puede descargar, como un MDB. Por lo tanto, debemos proteger las bases de datos de texto de la misma manera que los MDB. Cambie el nombre del sufijo de la base de datos de texto a .PHP. y unirse en la primera fila de la base de datos. De esta manera, la base de datos de texto será tratada como un archivo PHP y la ejecución finalizará en la primera línea. Es decir, se devuelve una página vacía para lograr el propósito de proteger la base de datos de texto.
Se filtró el camino equivocado
1. Causa de la vulnerabilidad:
Cuando PHP encuentra un error, proporcionará la ubicación, el número de línea y el motivo del script de error, por ejemplo:
Aviso: uso de prueba constante indefinida: se asume 'prueba' en D:interpubbigflytest.php en la línea 3
Mucha gente dice que no es gran cosa. Pero las consecuencias de filtrar la ruta real son inimaginables. Para algunos intrusos, esta información es muy importante. De hecho, muchos servidores ahora tienen este problema.
Algunos administradores de red simplemente configuran display_errors en el archivo de configuración PHP en Off para resolver el problema, pero creo que este método es demasiado negativo. A veces, realmente necesitamos que PHP devuelva información de error para depurar. Y cuando algo sale mal, es posible que también tengas que darle una explicación al usuario o incluso navegar a otra página.
2. Resolución de vulnerabilidad:
PHP ha proporcionado una función de manejo de errores personalizada set_error_handler() desde 4.1.0, pero pocos escritores de scripts lo saben. Entre los muchos foros de PHP, he visto sólo unos pocos que manejan esta situación. El uso de set_error_handler es el siguiente:
cadena set_error_handler (devolución de llamada error_handler [, int tipo_error])
Ahora utilizamos un manejo de errores personalizado para filtrar las rutas reales.
// Admin es la determinación de identidad del administrador, verdadero es el administrador.
// La función de manejo de errores personalizada debe tener estas cuatro variables de entrada $errno, $errstr, $errfile, $errline; de lo contrario, no será válida.
función my_error_handler($errno,$errstr,$errfile,$errline)
{
//Si no eres administrador, filtra la ruta real
si(!administrador)
{
$errfile=str_replace(getcwd(),"",$errfile);
$errstr=str_replace(getcwd(),"",$errstr);
}
cambiar($errno)
{
caso E_ERROR:
echo "ERROR: [ID $errno] $errstr (Línea: $errline de $errfile)
norte";
echo "El programa dejó de ejecutarse, comuníquese con el administrador.";
//Salga del script cuando encuentre un error de nivel de error
salida;
romper;
caso E_WARNING:
echo "ADVERTENCIA: [ID $errno] $errstr (Línea: $errline de $errfile)
norte";
romper;
predeterminado:
//No mostrar errores de nivel de aviso
romper;
}
}
//Establece el manejo de errores en la función my_error_handler
set_error_handler("mi_error_handler");
…
De esta forma, se puede resolver bien la contradicción entre seguridad y conveniencia de depuración. Y también puedes pensar en hacer que el mensaje de error sea más bonito para que coincida con el estilo del sitio web. Pero tenga en cuenta dos puntos:
(1) E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR y E_COMPILE_WARNING no serán procesados por este identificador, es decir, se mostrarán de la forma más original. Sin embargo, estos errores son causados por errores de compilación o del kernel de PHP y no ocurrirán en circunstancias normales.
(2) Después de usar set_error_handler(), error_reporting () dejará de ser válido. Es decir, todos los errores (excepto los errores mencionados anteriormente) se entregarán a la función personalizada para su procesamiento.
Para obtener más información sobre set_error_handler(), puede consultar el manual oficial de PHP.
POST vulnerabilidad
1. Causa de la vulnerabilidad:
Como se mencionó anteriormente, confiar en Register_globals para registrar variables es un mal hábito. En algunos programas de foros y libros de visitas, es aún más necesario verificar estrictamente el método de obtención de páginas y el intervalo de tiempo entre envíos. Para evitar publicaciones no deseadas y envíos externos. Echemos un vistazo al siguiente código para un programa de libro de visitas:
...
$texto1=flt_tags($texto1);
$texto2=flt_tags($texto2);
$text3=flt_tags($text3);
$fd=fopen("datos.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
...
Obviamente, si enviamos la URL "post.php?text1=testhaha&text2=testhaha&text3=testhaha". Los datos se escribirán en el archivo normalmente. Este programa no detecta el origen de las variables ni cómo el navegador obtuvo la página. Si enviamos varios envíos a esta página, se producirá una inundación. También hay algunos programas que aprovechan esta vulnerabilidad para publicar anuncios en foros o libros de visitas, lo cual es un comportamiento vergonzoso (el libro de visitas de mi amigo se inundó con más de 10 páginas en una semana, lo cual fue inútil).
2. Resolución de vulnerabilidad:
Antes de procesar y guardar datos, primero determine cómo obtiene el navegador la página. Utilice la variable $_SERVER["REQUEST_METHOD"] para obtener el método del navegador para obtener la página. Compruebe si es "POST". Utilice la sesión en el script para registrar si el usuario envía datos a través de canales normales (es decir, la página donde se completa el contenido del envío). O utilice $_SERVER["HTTP_REFERER"] para detectar esto, pero no se recomienda. Debido a que algunos navegadores no configuran REFERER, algunos firewalls también bloquearán REFERER. Además, también debemos verificar el contenido enviado para ver si hay contenido duplicado en la base de datos. Tome el libro de visitas como ejemplo y utilice Session para tomar la determinación:
En la página donde completa el contenido de navegación, agregamos en la parte frontal:
$_SESSION["allowgbookpost"]=time(); // La hora en que se completa el registro. En la página donde se aceptan y guardan los datos del mensaje, también usamos Session para realizar el siguiente procesamiento antes del procesamiento de datos:
if(strtoupper($_SERVER["REQUEST_METHOD"])!="POST"){ die("Error: No enviar externamente."); //Verifique si el método de adquisición de la página es POST
if(!isset($_SESSION["allowgbookpost"]) o (time()-$_SESSION["allowgbookpost"] < 10)){ die("Error: No enviar externamente." } //Verifique el mensaje Hora al completar
if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die("Error: el intervalo entre dos envíos de mensajes no debe ser inferior a 2 minutos. "); } //Verifique el intervalo de mensajes
unset($_SESSION["allowgbookpost"]); //Anule el registro de la variable enablegbookpost para evitar que múltiples envíos ingresen a la página de relleno al mismo tiempo
$_SESSION["gbookposttime"]=time(); //Registra la hora para enviar mensajes para evitar spam o ataques maliciosos
...
Procesamiento y almacenamiento de datos.
...
Después de tantas revisiones, su programa será mucho más seguro.