Não htmlspecialchars e mysql_real_escape_string manter meu seguro código PHP de injeção?

StackOverflow https://stackoverflow.com/questions/110575

Pergunta

Hoje cedo foi feita uma pergunta sobre estratégias de validação de entrada em aplicações web .

A resposta superior, no momento da escrita, sugere em PHP apenas usando htmlspecialchars e mysql_real_escape_string.

A minha pergunta é: É este sempre é suficiente? Há mais devemos saber? Onde é que estas funções quebrar?

Foi útil?

Solução

Quando se trata de consultas de banco de dados, sempre tentar e uso preparado consultas parametrizadas. As bibliotecas mysqli e PDO apoiar esta. Esta é infinitamente mais seguro do que o uso de funções escapando como mysql_real_escape_string.

Sim, mysql_real_escape_string é efetivamente apenas uma seqüência função escapar. Não é uma bala mágica. Tudo o que vai fazer é escapar caracteres perigosas, a fim de que eles podem ser seguro para uso em uma única string de consulta. No entanto, se você não higienizar suas entradas com antecedência, então você será vulnerável a certos vetores de ataque.

Imagine a seguinte SQL:

$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);

Você deve ser capaz de ver que este é vulnerável ao exploit.
Imagine que o parâmetro id continha o vetor de ataque comum:

1 OR 1=1

Não há nenhuma chars arriscados lá para codificar, por isso vai passar direto através do filtro escapar. deixando-nos:

SELECT fields FROM table WHERE id= 1 OR 1=1

O que é um belo vetor de injeção SQL e permitiria que o atacante para retornar todas as linhas. Ou

1 or is_admin=1 order by id limit 1

que produz

SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1

que permite que o invasor para retornar detalhes do primeiro administrador neste exemplo totalmente ficcional.

Embora estas funções são úteis, eles devem ser usados ??com cuidado. Você precisa se certificar de que todas as entradas da web são validados em algum grau. Neste caso, vemos que pode ser explorado porque não verificar se uma variável que estávamos usando como um número, era na verdade numérico. Em PHP você deve amplamente usar um conjunto de funções para verificar que as entradas sejam inteiros, carros alegóricos, alfanumérico etc. Mas quando se trata de SQL, atenção mais o valor da declaração preparada. O código acima teria sido seguro se fosse uma declaração preparada como as funções de banco de dados teria sabido que 1 OR 1=1 não é um literal válido.

Quanto htmlspecialchars(). Isso é um campo minado de seu próprio.

Há um problema real em PHP na medida em que tem toda uma variedade de diferentes funções escapando relacionados a HTML, e sem uma orientação clara sobre exatamente quais funções fazer o quê.

Em primeiro lugar, se você estiver dentro de uma tag HTML, você está em apuros real. Olhada

echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';

Já estamos dentro de uma tag HTML, de modo que não precisamos para fazer qualquer coisa perigosa. O nosso vetor de ataque poderia ser apenas javascript:alert(document.cookie)

Agora aparência HTML resultante como

<img src= "javascript:alert(document.cookie)" />

O ataque fica direto.

E fica ainda pior. Por quê? porque htmlspecialchars (quando chamado desta forma), apenas codifica aspas duplas e não individual. Então, se tivéssemos

echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";

O nosso mal atacante pode agora injetar inteiros novos parâmetros

pic.png' onclick='location.href=xxx' onmouseover='...

dá-nos!

<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />

Nestes casos, não há nenhuma bala mágica, você só tem que santise a entrada de si mesmo. Se você tentar filtrar os personagens ruins que você certamente irá falhar. Dê uma abordagem whitelist e só deixar passar os caracteres que são bons. Olhada na XSS Cheat Sheet para exemplos de como diversos vetores podem ser

Mesmo se você usar fora htmlspecialchars($string) de tags HTML, você ainda são vulneráveis ??a multi-byte vetores de ataque charset.

O mais eficaz que você pode ser é usar a combinação de mb_convert_encoding e htmlentities como segue.

$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');

Mesmo esta imagem Folhas IE6 vulneráveis, devido à maneira como ele lida com UTF. No entanto, você pode cair de volta para uma codificação mais limitados, tais como ISO-8859-1, até o uso do IE6 cai.

Para um estudo mais aprofundado para os problemas de vários bytes, consulte https://stackoverflow.com/a/12118602/1820

Outras dicas

Além de excelente resposta de Cheekysoft:

  • Sim, eles vão mantê-lo seguro, mas somente se eles são usados ??absolutamente corretamente. Usá-los incorretamente e você ainda vai ser vulnerável, e pode ter outros problemas (por exemplo a corrupção de dados)
  • Utilize parametrizado consultas em vez (como indicado acima). Você pode usá-los por meio de exemplo DOP ou através de um invólucro como PEAR DB
  • Certifique-se de que magic_quotes_gpc e magic_quotes_runtime estão fora em todos os momentos, e nunca se acidentalmente ligado, nem mesmo por alguns instantes. Estes são uma tentativa cedo e profundamente equivocada pelos desenvolvedores do PHP para evitar problemas de segurança (que destrói dados)

Não há realmente uma bala de prata para a prevenção de injeção HTML (por exemplo, Cross Site Scripting), mas você pode ser capaz de alcançá-lo mais facilmente se você estiver usando uma biblioteca ou um sistema de templates para a saída HTML. Leia a documentação para que para saber como escapar as coisas de forma adequada.

Em HTML, as coisas devem ser precedidos de forma diferente dependendo do contexto. Isto é especialmente verdadeiro de cordas sendo colocado em Javascript.

Eu definitivamente concordo com os posts acima, mas tenho uma pequena coisa a acrescentar, em resposta a resposta de Cheekysoft, especificamente:

Quando se trata de consultas de banco de dados, sempre tentar e uso preparado consultas parametrizadas. O mysqli e bibliotecas DOP apoiar esta. Isto é infinitamente mais seguro do que usar escapar funções tais como mysql_real_escape_string.

Sim, mysql_real_escape_string é efetivamente apenas uma seqüência escapar função. Não é uma bala mágica. Tudo o que vai fazer é escapar perigosa caracteres a fim de que eles podem ser seguro para uso em uma única string de consulta. No entanto, se você não higienizar o seu entradas com antecedência, então você será vulnerável a certos vetores de ataque.

Imagine a seguinte SQL:

$ result = "SELECT campos da tabela Where = id " .Mysql_real_escape_string ($ _ POST [ 'id']);

Você deve ser capaz de ver que este é vulneráveis ??à exploração. Imagine a id parâmetro contido o ataque comum vetor:

1 ou 1 = 1

Não há nenhuma chars arriscados lá para codificar, por isso vai passar em frente através do filtro de escape. Saindo nós:

SELECT campos da tabela WHERE id = 1 OR 1 = 1

I codificado uma função pouco rápida que eu coloquei na minha classe de banco de dados que irá retirar qualquer coisa que não é um número. Ele usa preg_replace, para que haja prov uma função pouco mais otimizado, mas funciona em uma pitada ...

function Numbers($input) {
  $input = preg_replace("/[^0-9]/","", $input);
  if($input == '') $input = 0;
  return $input;
}

Assim, em vez de usar

$ result = "SELECT campos da tabela WHERE id =" .mysqlrealescapestring ( "1 ou 1 = 1");

Gostaria de usar

$ result = "SELECT campos da tabela WHERE id =" .Numbers ( "1 OR 1 = 1");

e seria seguramente executar a consulta

campos SELECT da tabela WHERE id = 111

Claro, que só parou de exibir a linha correta, mas eu não acho que é um grande problema para quem está tentando sql injetar em seu site;)

Uma importante peça deste puzzle é contextos. Alguém envio "1 OR 1 = 1" como o ID não é um problema se você citar todos os argumentos em sua consulta:

SELECT fields FROM table WHERE id='".mysql_real_escape_string($_GET['id'])."'"

o que resulta em:

SELECT fields FROM table WHERE id='1 OR 1=1'

que é ineficaz. Desde que você está fugindo da cadeia, a entrada não pode sair do contexto string. Eu testei este, tanto quanto a versão 5.0.45 do MySQL, e usando um contexto de string para uma coluna inteira não causar quaisquer problemas.

$result = "SELECT fields FROM table WHERE id = ".(INT) $_GET['id'];

Funciona bem, ainda melhor em sistemas de 64 bits. Cuidado com suas limitações dos sistemas em abordar grandes números, porém, mas para ids banco de dados isso funciona muito bem 99% do tempo.

Você deve estar usando uma única função / método para a limpeza de seus valores também. Mesmo se esta função é apenas um wrapper para mysql_real_escape_string (). Por quê? Porque um dia, quando um exploit para o seu método preferido de limpeza de dados for encontrado, você só tem que atualizá-lo um só lugar, em vez de um em todo o sistema localizar e substituir.

porque, oh porque, você não incluir aspas em torno de entrada do usuário em sua instrução SQL? parece bastante tolo não! incluindo citações em sua instrução SQL tornaria "1 ou 1 = 1" uma tentativa infrutífera, não?

agora, você vai dizer: "o que acontece se o usuário inclui uma citação (ou aspas) na entrada?"

bem, fácil correção para que: citações usuário só remove input'd. por exemplo: input =~ s/'//g;. Agora, parece-me de qualquer maneira, que a entrada do usuário será garantido ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top