Когда * не * использовать подготовленные заявления?

Я перепроектирую веб-сайт, основанный на PHP, который использует минимальную базу данных. В исходной версии использовались «псевдоподготовленные-заявления» (функции PHP, которые выполняли кавычки и замену параметров), чтобы предотвратить атаки на инъекции и отделить логику базы данных от логики страницы.

Естественно было заменить эти специальные функции объектом, который использует PDO и реальные подготовленные заявления, но после того, как я прочитал их, я не уверен. PDO по-прежнему кажется отличной идеей, но одна из основных точек продажи подготовленных заявлений заключается в том, что они могут повторно использовать их … которых я никогда не сделаю. Вот моя настройка:

  • Все тривиально простые утверждения. Большинство из них находятся в форме SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1 SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1 . Самым сложным заявлением в партии является просто три таких выбора, соединенных вместе с UNION ALL s.
  • Каждый снимок страницы выполняет не более одного оператора и выполняет его только один раз.
  • Я нахожусь в размещенной среде и, следовательно, нахожусь на шлеме своих серверов, делая «стресс-тесты» лично.

Учитывая, что использование подготовленных заявлений будет, как минимум, удвоить число обращений к базам данных, которые я делаю, мне лучше избегать их? Могу ли я использовать PDO::MYSQL_ATTR_DIRECT_QUERY чтобы избежать накладных расходов на несколько поездок по базам данных, сохраняя при этом преимущества параметризации и защиты от инъекций? Или бинарные вызовы, используемые подготовленным API-интерфейсом, выполняются достаточно хорошо по сравнению с выполнением незаготовленных запросов, о которых я не должен беспокоиться об этом?

РЕДАКТИРОВАТЬ:

Спасибо за все хорошие советы, ребята. Это то, где я хотел бы отметить более одного ответа как «принятого» – много разных точек зрения. В конечном счете, однако, я должен дать Рик должное … без его ответа я бы блаженно ушел и сделал совершенно неправильную вещь даже после того, как посоветовал каждый. 🙂

Эмулированные подготовленные заявления!

Я думаю, вы хотите PDO :: ATTR_EMULATE_PREPARES. Это отключает собственные подготовленные операторы базы данных, но все же позволяет связывать запросы, чтобы предотвратить SQL-инъекцию и поддерживать ваш SQL-код. Из того, что я понимаю, PDO :: MYSQL_ATTR_DIRECT_QUERY полностью отключает привязки запросов.

Сегодняшнее правило разработки программного обеспечения: если оно ничего не сделает для вас, не используйте его.

Когда не использовать подготовленные заявления? Когда вы собираетесь запускать инструкцию только до того, как соединение db исчезнет.

Если не использовать параметры связанного запроса (что на самом деле большинство людей используют готовые заявления для получения)? Я склонен говорить «никогда», и я действительно хотел бы сказать «никогда», но реальность такова, что большинство баз данных и некоторые уровни абстракции db имеют определенные обстоятельства, при которых они не позволят вам связывать параметры, поэтому вы «вынуждены не использовать их в этих случаях. В любое другое время, тем не менее, это упростит вашу жизнь и ваш код станет более безопасным для их использования.

Я не знаком с PDO, но я бы поспорил, что он предоставляет механизм для запуска параметризованных запросов со значениями, указанными в том же вызове функции, если вы не хотите готовиться, а затем выполняетесь как отдельный шаг. (например, что-то вроде run_query("SELECT * FROM users WHERE id = ?", 1) или аналогичный.)

Кроме того, если вы посмотрите под капот, большинство слоев абстракции db подготовят запрос, а затем запустите его, даже если вы просто скажете ему выполнить статический оператор SQL. Таким образом, вы, вероятно, не спасаете поездку в дБ, избегая явных подготавливаний.

Подготовленные заявления используются тысячами людей и поэтому хорошо протестированы (и, следовательно, можно сделать вывод, что они достаточно безопасны). Ваше пользовательское решение используется только вами.

Шанс, что ваше пользовательское решение небезопасно, довольно велико. Используйте подготовленные заявления. Вы должны поддерживать меньше кода таким образом.

Преимущества подготовленных заявлений заключаются в следующем:

  • каждый запрос компилируется только один раз
  • mysql будет использовать более эффективный транспортный формат для отправки данных на сервер

Однако подготовленные заявления сохраняются только для каждого соединения. Если вы не используете пул соединений, не будет никакой пользы, если вы делаете только один оператор на странице. Тривиально простые запросы не выиграют от более эффективного транспортного формата.

Лично я бы не стал беспокоиться. Псевдоподготовленные утверждения, вероятно, будут полезны для безопасной переменной, которую они предположительно предоставляют.

Честно говоря, я не думаю, что вам следует беспокоиться об этом. Тем не менее, я помню, что ряд фреймворков доступа к данным в формате PHP поддерживал режимы подготовки операторов и режимы без подготовки. Если я правильно помню, PEAR: DB вернулся в тот же день.

Я столкнулся с той же проблемой, что и у вас, и у меня были свои собственные оговорки, поэтому вместо использования PDO я закончил писать свой собственный уровень базы данных с легким весом, который поддерживал подготовку и стандартные инструкции и выполнял правильное экранирование (предотвращение SQL-инъекций) в обоих случаев. Одна из моих других попыток с подготовкой заключается в том, что иногда более эффективно добавлять некоторый невоспроизводимый ввод в оператор, такой как … WHERE id IN (1, 2, 3 …).

Я недостаточно знаю о PDO, чтобы рассказать вам, какие у вас есть другие варианты. Тем не менее, я знаю, что у PHP есть функции, доступные для всех поддерживаемых ею поставщиков баз данных, и вы можете перевернуть свой собственный маленький слой поверх любого уровня доступа к данным, за которым вы застряли.