Declarações preparadas do PHP PDO do MySQL – problemas de desempenho versus segurança

Estou pensando em rewrite algum aplicativo de código aberto para meus propósitos para PDO e transactions usando o InnoDB (mysql_query e MyISAM agora).

Minha pergunta é: quais são os casos razoáveis ​​para usar declarações preparadas?

Porque em todos os lugares que eu estou lendo é declarado (mesmo em muitos posts aqui) que eu deveria usar declarações preparadas sempre e em todos os lugares por causa da 1. segurança e 2. desempenho. Mesmo o manual do PHP recomenda o uso de declarações preparadas e não mencionando a coisa de escape.

Você não pode negar o mecanismo de segurança. Mas, pensando nisso, pensa que ter que preparar a declaração toda vez e depois usá-la uma vez … Isso não faz sentido. Embora tenha que inserir 1000 vezes algumas variables ​​em uma única afirmação, isso faz sentido, mas é óbvio. Mas isso não é o que o eshop ou a placa comum é construída.

Então, como superar isso? Posso preparar minhas declarações em toda a aplicação e nomeá-las especificamente? Posso preparar várias declarações diferentes e usá-las pelo nome? Porque esta é a única solução razoável em que estou pensando (exceto a coisa 1000x).

Eu achei que esta mysql_real_escape é chamada $ pdo-> quote também para o propósito de uma única consulta. Por que não usar isso? Por que se preocupar com a preparação?

E o que você acha desse excelente artigo? http://blog.ulf-wendel.de/2008/pdo_mysqlnd-prepared-statements-again/

Você concorda com a sobrecarga causada pela preparação das declarações?

obrigado

Eu acho que isso cai na categoria “otimização prematura”.

Quão significativa é a sobrecarga? Você mediu isso? Isso afeta o desempenho do seu servidor?

As chances são de que não.


No lado positivo, você tem um ganho inegável em termos de segurança (o que deve ser uma grande preocupação para qualquer loja baseada na internet).

Na desvantagem, você corre o risco de afetar o desempenho. No link que você forneceu, mostra que a preparação de PDO mal implementada resulta em um desempenho ligeiramente inferior ao da declaração não preparada em algumas circunstâncias. A diferença de desempenho em 5000 execuções é de 0.298 segundos.

Insignificante. Ainda mais, quando você percebe que as consultas “não preparadas” são executadas sem as rotinas de sanitização de input que seriam necessárias para torná-las seguras em um ambiente ao vivo. Se você não usar as consultas preparadas, você precisa de alguma forma de sanitização de input para evitar ataques de SQL e, dependendo de como é feito, talvez seja necessário massagear os conjuntos de resultados de massagem.

No fundo, não existe um problema de desempenho significativo, mas existe um benefício de segurança significativo. Assim, a recomendação oficial de usar declarações preparadas.

Na sua pergunta, você fala de “o eshop comum”. O “eshop comum” nunca terá tráfego suficiente para se preocupar com o problema de desempenho, se houver um. O problema de segurança na outra extremidade …

Minha pergunta é: quais são os casos razoáveis ​​para usar declarações preparadas?

Todos eles. A comunidade é abertamente oposta ao uso de funções mysql_* .

Nota: alternativas sugeridas

O uso desta extensão é desencorajado. Em vez disso, a extensão MySQLi ou PDO_MySQL deve ser usada. Veja também MySQL: escolhendo uma API para obter mais informações.

Alternativas a esta function incluem:

  • mysqli_connect()
  • PDO::__construct()

fonte

Mas, pensando mais e mais, vem à mente que ter que preparar a declaração toda vez e depois usá-la uma vez … Não faz sentido

Você está negociando em um Geo para um Jaguar e você está reclamando que não gosta da Jaguar porque você nem sempre usa os aquecedores de assentos. Você não precisa estar consistentemente usando todas as funções de uma biblioteca para significar que é bom.

Eu achei que esta mysql_real_escape é chamada $ pdo-> quote também para o propósito de uma única consulta. Por que não usar isso? Por que se preocupar com a preparação?

Se você estiver usando esta function para criar instruções SQL, é altamente recomendável usar o PDO :: prepare () para preparar instruções SQL com parâmetros vinculados ao invés de usar o PDO :: quote () para interpolar a input do usuário para uma instrução SQL. As declarações preparadas com parâmetros vinculados não são apenas mais portáteis, mais convenientes, imunes à injeção de SQL, mas muitas vezes são muito mais rápidas de serem executadas do que as consultas interpoladas, pois o lado do servidor e do cliente podem armazenar em cache uma forma compilada da consulta. fonte

Minha pergunta é: quais são os casos razoáveis ​​para usar declarações preparadas?

Bem, na verdade, isso é difícil de dizer. Especialmente porque nem sequer conta quais aplicativos de código aberto você fala aqui.

Para dar-lhe um exemplo: Para um aplicativo de livro de visitas ultra-lame, DOP com declarações preparadas será a escolha perfeita, bem como para 99% de todos os outros aplicativos de código aberto lá fora. Mas, para alguns, isso realmente pode fazer a diferença. A parte importante aqui é: Você não contou nada sobre o aplicativo.

Como o database não é sem importância para um aplicativo, é o contrário também: o aplicativo não é sem importância para o database.

Então, você precisa compartilhar mais sobre esse aplicativo de código aberto “misterioso” que você pergunta ou precisa nos dizer o que exatamente você gostaria de saber. Porque geralmente, é simples: tome PDO. Mas em particular, há diferenças, então você precisa nos dizer qual é o aplicativo em específico, caso contrário sua pergunta já está respondida.

E btw., Se o aplicativo for um estilo mysql_ *, é muito mais fácil simplesmente replace pela interface mysqli_ *. Se você tivesse feito alguns realmente reescrevendo, mesmo apenas por diversão, você teria visto isso.

Então, melhor adicionar mais carne aqui ou viver com algumas respostas não tão precisas.

Embora esta questão seja bastante antiga, alguns tópicos não foram realmente discutidos, que devem ser delineados aqui para outros pesquisando o mesmo que o OP.

Para resumir tudo abaixo:

  • Sim, sempre use declarações preparadas
  • Sim, use PDO sobre mysqli sobre mysql. Desta forma, se você alternar sistemas de database, tudo o que você precisa fazer é atualizar as consultas em vez de consultas, chamadas de function e argumentos, dado que ela oferece suporte a declarações preparadas.
  • Sempre desinfecte dados fornecidos pelo usuário, apesar de usar instruções preparadas com parâmetros
  • Olhe para um DBAL (Database Abstraction Layer) para facilitar o trabalho com todos esses fatores e manipular consultas para atender às suas necessidades.

Existe o tópico de PDO :: ATTR_EMULATE_PREPARES, que aumentará o desempenho da chamada de consultas em cache no MySQL> = 5.1.21 quando a emulação for DESLIGADA, o que é DESLIGADO por padrão. O que significa que o PHP irá emular a preparação antes da execução enviá-lo para o database atual. O tempo entre emulado e não emulado é normalmente insignificante, a menos que seja trabalhado com um database externo (não localhost), como em uma nuvem, que pode ter uma taxa de ping anormalmente alta.

O cache também depende das suas configurações do MySQL no my.cnf, mas otimização do MySQL fora do escopo desta publicação.

 < ?php $pdo = new \PDO($connection_string); $pdo->setAttribute( \PDO::ATTR_EMULATE_PREPARES, false ); ?> 

Portanto, tenha em mente isso porque o mysqli_ não fornece uma API para a emulação do lado do cliente e sempre vai usar o MySQL para preparar declarações. http://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php

Apesar de ter resources semelhantes, existem diferenças e você pode precisar de resources que uma API oferece enquanto a outra não. Veja a referência do PHP ao escolher uma API sobre a outra: http://www.php.net/manual/en/mysqlinfo.api.choosing.php

Então, isso vai muito bem com o que você pediu, definindo suas declarações em toda a aplicação, pois as consultas armazenadas em cache seriam armazenadas em cache no servidor MySQL e não precisariam estar preparadas em toda a aplicação. O outro benefício é que as exceções na sua Consulta serão lançadas em prepare () em vez de executar () que ajuda no desenvolvimento para garantir que suas Consultas estejam corretas.

Independentemente disso, não há benefícios de desempenho do mundo real de se preparar ou não.

Outro benefício de declarações preparadas está funcionando com Transações se você usar o InnoDB para MySQL. Você pode iniciar uma transação, inserir um registro, obter o último identificador de inserção, atualizar outra tabela, excluir de outro e, se alguma coisa falhar ao longo do caminho, você pode roloBack () antes que a transação acontecesse. Caso contrário, cometer as alterações se você escolher. Por exemplo, trabalhando com um novo pedido e configurando a coluna do último pedido do usuário para o novo ID da ordem e excluindo um pedido pendente, mas o tipo de pagamento fornecido não atendeu aos critérios para colocar ordens da tabela order_flags, para que você possa rolarBack () e mostrar ao usuário uma mensagem de erro amigável.

Quanto à segurança, estou bastante desconcertado, ninguém tocou nisso. Ao enviar qualquer dado fornecido pelo usuário a qualquer sistema, incluindo PHP e MySQL, desinfecte-o e padronize-o. Sim declarações preparadas fornecem alguma segurança quando se trata de escaping dos dados, mas NÃO é 100% à prova de bala.

Portanto, sempre usar declarações preparadas é muito mais benéfico do que não com perda de desempenho real e alguns benefícios com o armazenamento em cache, mas você ainda deve desinfetar os dados fornecidos pelo usuário. Um passo é digitar as variables ​​para o tipo de dados desejado com o qual você está trabalhando. O uso de objects facilitaria ainda mais isso, pois você trabalha dentro de um único Modelo para os tipos de dados, em vez de ter que se lembrar de cada vez que você trabalha com os mesmos dados.

Para adicionar o acima, você deve procurar uma camada de abstração de database que use DOP. Por exemplo, Doctrine DBAL: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html

Os benefícios adicionais de trabalhar com um DBO + PDO são

  • Você pode padronizar e encurtar a quantidade de trabalho que você precisa fazer.
  • Ajuda na sanitização de dados fornecidos pelo usuário
  • Facilite manipular consultas complexas
  • Use transactions aninhadas
  • Alternar facilmente entre bancos de dados
  • Seu código torna-se mais portátil e utilizável em outros projetos

Por exemplo, eu estendi o PDO e supero os methods query (), fetchAll () e fetch () para que eles sempre usassem declarações preparadas e para que eu pudesse escrever instruções SQL dentro de fetch () ou fetchAll () em vez de escrever tudo de novo. POR EXEMPLO:

 < ?php $pdo = new PDOEnhanced( $connection ); $pdo->fetchAll( "SELECT * FROM foo WHERE bar = 'hi'", PDO::FETCH_OBJ ); //would automatically provide $stmt = $pdo->prepare( "SELECT * FROM foo WHERE bar=?" ); $stmt->execute( array( 'hi' ) ); $resultSet = $stmt->fetchAll( PDO::FETCH_OBJ ) ?> 

Quanto às pessoas que sugerem que o estilo mysql_ *, é muito mais fácil simplesmente replace pela mysqli_ * API. Não é o caso. Uma grande parte das funções mysql_ * foram excluídas ou tiveram alterações de argumentos com mysqli_ * Consulte: http://php.net/manual/en/mysqli.summary.php

No entanto, você pode obter um conversor lançado pela Oracle para facilitar o processo: https://wikis.oracle.com/display/mysql/Converting+to+MySQLi

Tenha em mente que é um analisador de texto de fonte de arquivo e não é 100% preciso, então valide as alterações antes de juntá-las. Também irá adicionar uma quantidade significativa de despesas gerais para os globais que ele cria.