Должны ли мы всегда связывать наши операторы SQL?

Я изучал bindValue() PDO bindValue() . Я знаю, что подготовка моих операторов SQL с PDO ведет к тому, что SQL-инъекции происходят.

Пример кода:

 $stmt = $dbh->prepare('SELECT * FROM articles WHERE id = :id AND title = :title'); $stmt->bindValue(':id', PDO::PARAM_INT); $stmt->bindValue(':title', PDO::PARAM_STR); $stmt->execute(); 

Связывая идентификатор как число, а заголовок был строкой, мы можем ограничить ущерб, нанесенный, когда кто-то пытается выполнить SQL-инъекцию внутри кода.

Должны ли мы всегда связывать наши значения с PDO::PARAM_ поэтому мы можем ограничить то, что можно извлечь из базы данных в SQL-инъекции? Означает ли это повышение безопасности с помощью PDO при выполнении bindValue() ?

Solutions Collecting From Web of "Должны ли мы всегда связывать наши операторы SQL?"

В одном есть два вопроса. Важно не путать их

  1. Должен ли мы всегда использовать заполнитель для представления переменных данных в запросе?
  2. Должны ли мы всегда использовать определенную функцию в коде приложения, чтобы следовать приведенному выше правилу?
    Кроме того, из пояснения в комментариях по открытому сообщению можно видеть третий вопрос:
  3. Должен ли мы всегда использовать третий параметр, или это нормально, если PDO связывает все параметры как строки по умолчанию?

1. Для первого вопроса ответ абсолютно и определенно – ДА.

Хотя для второго, ради здравого смысла кода и СУХОЙ –

2. Избегайте ручного связывания, когда это возможно.

Существует много способов избежать ручной привязки. Некоторые из них:

  • ORM – отличное решение для простых операций CRUD и должно иметь в современном приложении. Он полностью скроет SQL от вас, сделав привязку за кулисами:

     $user = User::model()->findByPk($id); 
  • Query Builder – это также путь, который скрывает SQL в некоторых PHP-операциях, но снова скрывает привязку за кулисами:

     $user = $db->select('*')->from('users')->where('id = ?', $id)->fetch(); 
  • некоторые библиотеки абстракции могут позаботиться о переданных данных с помощью типа-намеченных заполнителей , снова спрятав фактическое привязку:

     $user = $db->getRow("SELECT * FROM users WHERE id =?i", $id); 
  • если вы все еще используете PHP в прошлом столетии и имеете необработанный PDO по всему коду – тогда вы можете передать свои переменные в execute (), сохраняя при этом много ввода:

     $stmt = $dbh->prepare('SELECT * FROM users WHERE id = ?'); $stmt->execute([$id]); $user = $stmt->fetch(); 

Начиная с третьего вопроса – пока вы связываете числа как строки (но не наоборот) –

3. С mysql все в порядке, чтобы отправлять почти каждый параметр в виде строки

поскольку mysql всегда будет преобразовывать ваши данные в соответствующий тип. Единственный известный мне случай – это предложение LIMIT, в котором вы не можете форматировать число как строку, поэтому единственным связанным случаем является тот, когда PDO установлен в режиме эмуляции, и вы должны передать параметр в предложении LIMIT . Во всех остальных случаях вы можете опустить третий параметр, а также явный вызов bindValue() без каких-либо проблем.

Вы должны обязательно использовать API prepare и передавать значения отдельно от запроса, в отличие от простой интерполяции строк (например, "SELECT * FROM foo WHERE bar = '$baz'"плохо ).

Для параметров привязки у вас есть три варианта:

  • bindParam
  • bindValue
  • execute

Неважно, какой из них вы используете, все они одинаково безопасны. См. Ответы на некоторые подробности о различиях:

  • Путаница между bindValue () и bindParam ()?
  • Использование PDO без привязки

При использовании bindParam или bindValue передача третьего аргумента типа PDO::PARAM_ является необязательной. Если вы его не передадите, по умолчанию используется привязка аргумента как строки. Это означает, что вы можете получить эквивалентный запрос ... WHERE foo = '42' вместо ... WHERE foo = 42 . Это зависит от вашей базы данных, как она справится с этим. MySQL будет автоматически вводить строку в число, как это делает PHP (например, в '42' + 1 ). Другие типы баз данных могут быть более суетливыми в отношении типов.

Опять же, все варианты одинаково безопасны. Если вы пытаетесь связать строку 'foo' с помощью PDO::PARAM_INT , строка будет отлита к целому числу и, соответственно, привязана как значение 0 . Нет возможности для инъекций.

Да, вы всегда должны связывать params с подготовленным оператором. Это более безопасно и ограничивает SQL-инъекцию. Но это не единственное, что нужно сделать для запроса параметров: необходим правильный тип управления, лучше всего, если вы сопоставляете строку с объектом и генерируете исключение, если оно имеет недопустимые данные.

Надеюсь, я могу быть полезен!

Да , привязка – это путь. Или параметризованные запросы, которые имеют более обобщенный термин.

@Theo делает замечательную работу, объясняя, почему параметризованные запросы – это способ пойти

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