Pergunta

Então, eu sou um desenvolvedor de PHP um pouco experiente e sou 'fazendo a maldita coisa' desde 2007; No entanto, ainda sou relativamente n00bish quando se trata de proteger meus aplicativos. Da maneira que eu realmente não sei tudo o que sei que poderia e deveria.

Eu peguei Garantir aplicativos da Web PHP E estou lendo meu caminho, testando as coisas ao longo do caminho. Tenho algumas perguntas para o grupo geral que se relaciona com a consulta de banco de dados (principalmente sob o MySQL):

Ao criar aplicativos que colocam dados em um banco de dados, o mysql_real_escape_string e a verificação geral (is_numeric etc) nos dados de entrada o suficiente? E os outros tipos de ataques diferentes da injeção de SQL.

Alguém poderia explicar procedimentos armazenados e declarações preparadas com um pouco mais de informação do que - você as faz e faz chamadas para eles. Eu gostaria de saber como eles funcionam, que validação acontece nos bastidores.

Eu trabalho em um ambiente ligado ao PHP4 e o PHP5 não é uma opção por enquanto. Alguém já esteve nessa posição antes, o que você fez para proteger seus aplicativos enquanto todas as crianças legais estão usando essa nova interface MySQLI?

Quais são algumas boas práticas gerais que as pessoas descobriram como vantajoso, ênfase na criação de uma infraestrutura capaz de suportar atualizações e possíveis migrações (como a movimentação de Php4 para Php5).

Nota: A pesquisa não conseguiu encontrar nada semelhante a isso que atingisse a segurança PHP-MYSQL.

Foi útil?

Solução

Minhas recomendações:

  1. Ditch Mysqli a favor de PDO (com o driver MySQL)
  2. Use declarações preparadas para pareméricas da PDO

Você pode então fazer algo como:

$pdo_obj = new PDO( 'mysql:server=localhost; dbname=mydatabase', 
                    $dbusername, $dbpassword );

$sql = 'SELECT column FROM table WHERE condition=:condition';
$params = array( ':condition' => 1 );

$statement = $pdo_obj->prepare( $sql, 
    array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );
$statement->execute( $params );
$result = $statement->fetchAll( PDO::FETCH_ASSOC );

Prós:

  1. Não há mais fuga manual, já que a PDO faz tudo para você!
  2. É relativamente fácil trocar o banco de dados de repente.

Contras:

  • Eu não consigo pensar em nenhum.

Outras dicas

A resposta de Javier, que tem o link OWASP, é um bom começo.

Há mais algumas coisas que você pode fazer mais:

  1. Em relação aos ataques de injeção de SQL, você pode escrever uma função que removerá instruções SQL comuns da entrada como "Drop" ou "Excluir * Where", assim:

    * $ SQLARRAY = Array ("Drop", "ou 1 = 1", "Union Select", "Selecione * de", "Selecionar host", "Criar tabela", "From Usuários", "Usuários onde"); *

    Em seguida, escreva a função que verificará sua entrada em relação a esta matriz. Verifique se qualquer coisa dentro do $ SQLARRAY não será uma entrada comum de seus usuários. (Não se esqueça de usar o StrTolower nisso, obrigado Lou).

  2. Não tenho certeza se o Memcache funciona com o PHP 4, mas você pode colocar um pouco de proteção de spam com o Memcache, permitindo apenas um determinado acesso IP remoto ao processo.

  3. Privilégios é importante. Se você precisar apenas inserir privilégios (por exemplo, processamento de pedidos), faça o login no banco de dados na página do processo de pedido com um usuário que só possui inserção e talvez selecione privilégios. Isso significa que, mesmo que uma injeção de SQL tenha sido concluído, eles só poderiam executar consultas de inserção / seleção e não excluir ou reestruturar.

  4. Coloque arquivos importantes de processamento de PHP em um diretório como /incluir. Em seguida, proibir todo o acesso do IPS a esse /incluir diretório.

  5. Coloque um MD5 salgado com o agente + remoteip do usuário + seu sal na sessão do usuário e faça com que ele verifique em cada carga que o MD5 correto está em seu cookie.

  6. Proibir certos cabeçalhos (http://www.owasp.org/index.php/testing_for_http_methods_and_xst). Não perdoe o put (se você não precisar de uploads de arquivo)/Trace/Connect/Excluir cabeçalhos.

Normalmente não trabalho com PHP, por isso não posso fornecer conselhos especificamente direcionados aos seus requisitos, mas sugiro que você dê uma olhada na página OWASP, principalmente o relatório das 10 principais vulnerabilidades: http://www.owasp.org/index.php/top_10_2007

Nessa página, para cada vulnerabilidade, você obtém uma lista das coisas que pode fazer para evitar o problema em diferentes plataformas (.NET, Java, PHP, etc.)

Em relação às declarações preparadas, eles funcionam, informando o mecanismo de banco de dados quantos parâmetros e que tipos esperam durante uma consulta específica, usando essas informações, o mecanismo pode entender quais caracteres fazem parte do parâmetro real e não algo que deve ser analisado como SQL como um '(apóstrofe) como parte dos dados em vez de um' como delimitador de string. Desculpe, não posso fornecer mais informações direcionadas ao PHP, mas espero que isso ajude.

AFAIK, PHP/MYSQL geralmente não possui consultas parametrizadas.

Usando sprintf() com mysql_real_escape_string() deve funcionar muito bem. Se você usar seqüências de formato apropriadas para sprintf() (por exemplo, "%d" para números inteiros) Você deve estar bastante seguro.

Eu posso estar errado, mas não deveria ser suficiente para usar mysql_real_escape_string nos dados fornecidos pelo usuário?

a menos que sejam números, nesse caso, você deve garantir que eles sejam de fato números usando, por exemplo, ctype_digit ou is_numeric ou sprintf (usando %d ou %u para forçar a entrada em um número).

Além disso, ter um usuário MySQL serarado para seus scripts PHP que só podem selecionar, inserir, atualizar e excluir é provavelmente uma boa ideia ...


Exemplo de Php.net

Exemplo #3 Uma consulta de "prática recomendada"

O uso do mysql_real_escape_string () em torno de cada variável impede a injeção SQL. Este exemplo demonstra o método da "prática recomendada" para consultar um banco de dados, independentemente da configuração de Quotes Magic.

A consulta agora será executada corretamente e os ataques de injeção de SQL não funcionarão.

   <?php
    if (isset($_POST['product_name']) && isset($_POST['product_description']) && isset($_POST['user_id'])) {
        // Connect

        $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password');

        if(!is_resource($link)) {

            echo "Failed to connect to the server\n";
            // ... log the error properly

        } else {

            // Reverse magic_quotes_gpc/magic_quotes_sybase effects on those vars if ON.

            if(get_magic_quotes_gpc()) {
                $product_name        = stripslashes($_POST['product_name']);
                $product_description = stripslashes($_POST['product_description']);
            } else {
                $product_name        = $_POST['product_name'];
                $product_description = $_POST['product_description'];
            }

            // Make a safe query
            $query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)",
                        mysql_real_escape_string($product_name, $link),
                        mysql_real_escape_string($product_description, $link),
                        $_POST['user_id']);

            mysql_query($query, $link);

            if (mysql_affected_rows($link) > 0) {
                echo "Product inserted\n";
            }
        }
    } else {
        echo "Fill the form properly\n";
    }

Use procedimentos armazenados para qualquer atividade que envolva os armas no banco de dados e use parâmetros de ligação para todas as seleções.

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