Abuso de inclusão
1. Causa da vulnerabilidade:
Incluir é a função mais comumente usada na escrita de sites PHP e oferece suporte a caminhos relativos. Existem muitos scripts PHP que usam diretamente uma variável de entrada como parâmetro de inclusão, causando vulnerabilidades como referência arbitrária de script e vazamento absoluto de caminho. Observe o seguinte código:
...
$includepage=$_GET["includepage"];
include($includepágina);
...
Obviamente, só precisamos enviar diferentes variáveis Includepage para obter a página desejada. Se você enviar uma página que não existe, poderá causar erro no script PHP e vazar o caminho absoluto real (a solução para esse problema é explicada no artigo a seguir).
2. Resolução de vulnerabilidades:
A solução para esta vulnerabilidade é muito simples, que consiste primeiro em determinar se a página existe e depois incluí-la. Ou, mais estritamente, use um array para especificar os arquivos que podem ser incluídos. Observe o seguinte código:
$pagelist=array("test1.php","test2.php","test3.php"); //Isso especifica os arquivos que podem ser incluídos
if(isset($_GET["includepage"])) //Determina se existe $includepage
{
$includepage=$_GET["includepage"];
foreach($pagelist as $prepage)
{
if($includepage==$prepage) //Verifica se o arquivo está na lista de permitidos
{
include($pré-página);
$checkfind=true;
quebrar;
}
}
if($checkfind==true){ não definido($checkfind });
else{ die("Página de referência inválida!");
}
Isso resolverá muito bem o problema.
Dica: As funções com este problema incluem: require(), require_once(), include_once(), readfile(), etc. Você também deve prestar atenção ao escrever.
Variáveis de entrada não são filtradas
1. Causa da vulnerabilidade:
Essa vulnerabilidade apareceu há muito tempo no ASP, causando inúmeras vulnerabilidades de injeção naquela época. Mas como o PHP tinha uma pequena influência na época, muitas pessoas não conseguiam prestar atenção nisso. Para PHP, o impacto desta vulnerabilidade é maior do que para ASP, porque mais scripts PHP usam bancos de dados de texto. Claro, há também o problema da injeção de instruções SQL. Para dar um exemplo mais clássico, o primeiro é o banco de dados:
$id=$_GET["id"];
$query="SELECT * FROM my_table where id='".$id."'" //Uma vulnerabilidade de injeção de SQL muito clássica
$resultado=mysql_query($query);
É óbvio aqui que podemos usar injeção para obter outros conteúdos do banco de dados. Não vou descrever isso em detalhes aqui. Assim como a injeção de ASP, você pode dar uma olhada nas defesas pretas anteriores. Em seguida, examinamos o problema dos bancos de dados de texto:
$texto1=$_POST["texto1"];
$texto2=$_POST["texto2"];
$text3=$_POST["text3"];
$fd=fopen("teste.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
A vulnerabilidade do texto é possivelmente ainda mais grave. Se inserirmos um pequeno pedaço de código PHP na variável enviada, podemos transformar esse banco de dados de texto test.php em um backdoor PHP. Até mesmo inserir o código de upload nos permite fazer upload de um backdoor PHP completo. Então aumente os privilégios e o servidor será seu.
2. Resolução de vulnerabilidades:
A solução para esta vulnerabilidade é na verdade muito simples, que consiste em filtrar rigorosamente todas as variáveis submetidas. Substitua alguns caracteres sensíveis. Podemos substituir o conteúdo do HTML com a ajuda da função htmlspecialchars() fornecida pelo PHP. Aqui está um exemplo:
//Constrói função de filtro www.knowsky.com
função flt_tags($texto)
{
$badwords=array("Foda-se","foda-se"); //Lista de filtro de palavras
$texto=rtrim($texto);
foreach($badwords as $badword) //Filtre o vocabulário aqui
{
if(stristr($text,$badword)==true){ die("Erro: O conteúdo que você enviou contém palavras sensíveis, por favor não envie conteúdo sensível.");
}
$text=htmlspecialchars($text); //substituição do HTML
//Essas duas linhas substituem o retorno de carro por
$text=str_replace("r","
",$texto);
$text=str_replace("n","",$text);
$text=str_replace("&line;","│",$text); //Substitua o separador de banco de dados de texto "&line;" pela largura total "│"
$text=preg_replace("/s{ 2 }/"," ",$text);
$text=preg_replace("/t/"," ",$text); // Ainda substituindo espaços
if(get_magic_quotes_gpc()){ $text=stripslashes($text }); //Se magic_quotes estiver ativado, substitua '
retornar $texto;
}
$texto1=$_POST["texto1"];
$texto2=$_POST["texto2"];
$text3=$_POST["text3"];
//Filtrar todas as entradas
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);
$fd=fopen("teste.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
Após alguma substituição e filtragem, você pode gravar os dados com segurança em texto ou banco de dados.
O julgamento do administrador está incompleto
1. Causa da vulnerabilidade:
Usamos PHP para escrever scripts, que geralmente envolvem permissões de administrador. Alguns scripts apenas julgam “sim” as permissões do administrador, mas geralmente ignoram o julgamento “não”. Quando register_globals estiver ativado no arquivo de configuração do PHP (ele está desativado por padrão nas versões posteriores à 4.2.0, mas muitas pessoas o ativam por conveniência, o que é um comportamento extremamente perigoso), haverá situações em que variáveis são enviadas para representar administradores. Vamos dar uma olhada no código de exemplo:
$cookiesign="admincookiesign"; //Determina se a variável de cookie do Admin
$adminsign=$_COOKIE["sign"]; //Obtém a variável de cookie do usuário
if($adminsign==$cookiesign)
{
$admin=verdadeiro;
}
if($admin){ echo "Agora você é um administrador.";
Parece muito seguro, haha. Agora assumimos que register_globals está ativado no arquivo de configuração do PHP. Enviamos o endereço "test.php?admin=true", você viu o resultado? Embora não tenhamos o cookie correto, porque register_globals está ativado, a variável admin que enviamos é automaticamente registrada como verdadeira. Além disso, o script carece de um julgamento “não”, o que nos permite obter permissões de administrador com sucesso através de admin=true. Este problema existe na maioria dos sites e fóruns.
2. Resolução de vulnerabilidades:
Para resolver esse problema, precisamos apenas adicionar um julgamento “não” ao administrador no script. Ainda assumimos que register_globals está ativado no arquivo de configuração do PHP. Dê uma olhada no código:
$cookiesign="admincookiesign"; //Determina se a variável de cookie do Admin
$adminsign=$_COOKIE["sign"]; //Obtém a variável de cookie do usuário
if($adminsign==$cookiesign)
{
$admin=verdadeiro;
}
outro
{
$admin=falso;
}
if($admin){ echo "Agora você é um administrador.";
Desta forma, mesmo que o invasor envie a variável admin=true sem o cookie correto, o script definirá $admin como False em julgamentos futuros. Isso resolve parte do problema. No entanto, como $admin é uma variável, se ocorrer uma brecha em outras referências de script no futuro e $admin for reatribuído, ocorrerá uma nova crise. Portanto, devemos usar constantes para armazenar a determinação das permissões do administrador. Use a instrução Define() para definir uma constante admin para registrar as permissões do administrador. Se for reatribuída após isso, ocorrerá um erro, atingindo o objetivo de proteção. Observe o seguinte código:
$cookiesign="admincookiesign"; //Determina se a variável de cookie do Admin
$adminsign=$_COOKIE["sign"]; //Obtém a variável de cookie do usuário
if($adminsign==$cookiesign)
{
definir(administrador,verdadeiro);
}
outro
{
definir(admin,falso);
}
if(admin){ echo "Agora você está no status de administrador.";
Vale ressaltar que utilizamos a instrução Define, portanto, ao chamar a constante Admin, não adicione habitualmente o símbolo da variável $ na frente, mas use Admin e !admin.
Banco de dados de texto exposto
1. Causa da vulnerabilidade:
Conforme mencionado anteriormente, devido à grande flexibilidade das bases de dados de texto, nenhum suporte externo é necessário. Além disso, o PHP possui recursos de processamento de arquivos muito fortes, portanto, bancos de dados de texto são amplamente utilizados em scripts PHP. Existem até vários bons programas de fórum que usam bancos de dados de texto. Mas há ganhos e perdas, e a segurança dos bancos de dados de texto é menor do que outros bancos de dados.
2. Resolução de vulnerabilidades:
O banco de dados de texto funciona como um arquivo comum, que pode ser baixado, assim como um MDB. Portanto, precisamos proteger os bancos de dados de texto da mesma forma que os MDBs. Altere o nome do sufixo do banco de dados de texto para .PHP. e junte-se à primeira linha do banco de dados. Desta forma o banco de dados de texto será tratado como um arquivo PHP e a execução será encerrada na primeira linha. Ou seja, uma página vazia é retornada para atingir o objetivo de proteger o banco de dados de texto.
Vazamento de caminho errado
1. Causa da vulnerabilidade:
Quando o PHP encontra um erro, ele fornecerá a localização, o número da linha e o motivo do script do erro, por exemplo:
Aviso: Uso de teste constante indefinido - assumido 'teste' em D:interpubbigflytest.php na linha 3
Muita gente diz que não é grande coisa. Mas as consequências do vazamento do caminho real são inimagináveis. Para alguns intrusos, esta informação é muito importante. Na verdade, muitos servidores agora enfrentam esse problema.
Alguns administradores de rede simplesmente definem display_errors no arquivo de configuração do PHP como Off para resolver o problema, mas acho que esse método é muito negativo. Às vezes, realmente precisamos que o PHP retorne informações de erro para depuração. E quando algo dá errado, você também pode precisar dar uma explicação ao usuário ou até mesmo navegar para outra página.
2. Resolução de vulnerabilidades:
O PHP fornece uma função de manipulação de erros personalizada function set_error_handler() desde a versão 4.1.0, mas poucos escritores de scripts sabem disso. Entre os muitos fóruns de PHP, vi apenas alguns lidarem com essa situação. O uso de set_error_handler é o seguinte:
string set_error_handler (retorno de chamada error_handler [, int error_types])
Agora usamos tratamento de erros personalizado para filtrar os caminhos reais.
//Admin é a determinação da identidade do administrador, true é o administrador.
//A função personalizada de tratamento de erros deve ter estas quatro variáveis de entrada $errno, $errstr, $errfile, $errline, caso contrário será inválida.
função meu_error_handler($errno,$errstr,$errfile,$errline)
{
//Se você não for administrador, filtre o caminho real
se(!admin)
{
$errfile=str_replace(getcwd(),"",$errfile);
$errstr=str_replace(getcwd(),"",$errstr);
}
switch($errno)
{
caso E_ERROR:
echo "ERRO: [ID $errno] $errstr (Linha: $errline de $errfile)
n";
echo "O programa parou de funcionar, entre em contato com o administrador.";
//Sai do script ao encontrar um erro de nível de erro
saída;
quebra;
caso E_WARNING:
echo "AVISO: [ID $errno] $errstr (Linha: $errline de $errfile)
n";
quebrar;
padrão:
//Não exibe erros de nível de aviso
quebrar;
}
}
//Definir tratamento de erros para a função my_error_handler
set_error_handler("meu_error_handler");
…
Desta forma, a contradição entre segurança e conveniência de depuração pode ser bem resolvida. E você também pode pensar em tornar a mensagem de erro mais bonita para combinar com o estilo do site. Mas observe dois pontos:
(1) E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR e E_COMPILE_WARNING não serão processados por este identificador, ou seja, serão exibidos da forma mais original. No entanto, esses erros são causados por erros de compilação ou do kernel do PHP e não ocorrerão em circunstâncias normais.
(2) Após usar set_error_handler(), error_reporting() será inválido. Ou seja, todos os erros (exceto os erros mencionados acima) serão entregues à função personalizada para processamento.
Para outras informações sobre set_error_handler(), você pode consultar o manual oficial do PHP.
Vulnerabilidade POST
1. Causa da vulnerabilidade:
Como mencionado antes, confiar em register_globals para registrar variáveis é um mau hábito. Em alguns programas de livros de visitas e fóruns, é ainda mais necessário verificar rigorosamente o método de obtenção das páginas e o intervalo de tempo entre os envios. Para evitar postagens de spam e envios externos. Vamos dar uma olhada no seguinte código para um programa de livro de visitas:
...
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);
$fd=fopen("dados.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
...
Obviamente, se enviarmos a URL "post.php?text1=testhaha&text2=testhaha&text3=testhaha". Os dados serão gravados no arquivo normalmente. Este programa não detecta a origem das variáveis e como o navegador obteve a página. Se enviarmos vários envios para esta página, isso causará inundação. Existem também alguns softwares que aproveitam esta vulnerabilidade para postar anúncios em fóruns ou livros de visitas, o que é um comportamento vergonhoso (o livro de visitas do meu amigo foi inundado com mais de 10 páginas em uma semana, o que foi inútil).
2. Resolução de vulnerabilidades:
Antes de processar e salvar dados, primeiro determine como o navegador obtém a página. Use a variável $_SERVER["REQUEST_METHOD"] para obter o método do navegador para obter a página. Verifique se é "POST". Use session no script para registrar se o usuário envia dados pelos canais normais (ou seja, a página onde o conteúdo do envio é preenchido). Ou use $_SERVER["HTTP_REFERER"] para detectar isso, mas isso não é recomendado. Como alguns navegadores não configuram REFERER, alguns firewalls também bloquearão REFERER. Além disso, também precisamos verificar o conteúdo enviado para ver se há conteúdo duplicado no banco de dados. Tome o livro de visitas como exemplo, use Session para fazer a determinação:
Na página onde você preenche o conteúdo da navegação, adicionamos no front end:
$_SESSION["allowgbookpost"]=time(); //O horário em que o registro é preenchido. Na página onde os dados da mensagem são aceitos e salvos, também usamos Session para realizar o seguinte processamento antes do processamento dos dados:
if(strtoupper($_SERVER["REQUEST_METHOD"])!="POST"){ die("Erro: Não enviar externamente."); //Verifique se o método de aquisição da página é POST.
if(!isset($_SESSION["allowgbookpost"]) or (time()-$_SESSION["allowgbookpost"] < 10)){ die("Erro: Não enviar externamente."); Hora de preencher
if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die("Erro: O intervalo entre dois envios de mensagens não deve ser inferior a 2 minutos. "); } //Verifica o intervalo da mensagem
unset($_SESSION["allowgbookpost"]); //Cancela o registro da variável Allowgbookpost para evitar que vários envios entrem na página de preenchimento ao mesmo tempo
$_SESSION["gbookposttime"]=time(); //Registra o horário de envio das mensagens para evitar spam ou ataques maliciosos
...
Processamento e armazenamento de dados
...
Após tantas revisões, seu programa ficará muito mais seguro.