Как PreparedStatement предотвращает или предотвращает SQL-инъекцию?

Я знаю, что PreparedStatements избегает/предотвращает внедрение SQL. Как оно это делает? Будет ли окончательный запрос формы, который построен с использованием PreparedStatements, будет строкой или иначе?

+93
источник поделиться
9 ответов

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

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

+61
источник

Рассмотрим два способа сделать одно и то же:

PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();

или

PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();

Если "пользователь" пришел с пользовательского ввода, а пользовательский ввод был

Robert'); DROP TABLE students; --

Тогда, в первом случае, вас будут закрывать. Во-вторых, вы были бы в безопасности, и Маленькие Bobby Tables были бы зарегистрированы для вашей школы.

+156
источник
другие ответы

Связанные вопросы


Похожие вопросы

Чтобы понять, как PreparedStatement предотвращает внедрение SQL, нам нужно понять этапы выполнения SQL-запроса.

1. Фаза компиляции. 2. Фаза выполнения.

Всякий раз, когда SQL Server engine получает запрос, он должен проходить через фазы ниже,

Query Execution Phases

  1. Фаза Parsing и Normalization: на этом этапе Query проверяется на синтаксис и семантику. Он проверяет, существуют ли таблицы ссылок и столбцы, используемые в запросе, или нет. У него также есть много других задач, но не стоит подробно останавливаться.

  2. Фаза компиляции: на этом этапе ключевые слова, используемые в запросе типа select, from, where и т.д., Преобразуются в формат, понятный машине. Это этап, когда запрос интерпретируется, и принимается соответствующее действие. У него также есть много других задач, но не стоит подробно останавливаться.

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

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

  5. Фаза выполнения: на этом этапе запрос выполнен, и данные возвращаются пользователю как объект ResultSet.

Поведение API PreparedStatement на вышеуказанных шагах

  1. PreparedStatements не являются полными SQL-запросами и содержат заполнители (-ы), которые во время выполнения заменяются фактическими данными, предоставленными пользователем.

  2. Всякий раз, когда какой-либо PreparedStatment, содержащий заполнители, передается в механизм SQL Server, он проходит через фазы ниже

    1. Фаза анализа и нормализации
    2. Фаза компиляции
    3. Оптимизатор запросов
    4. Кэш (скомпилированный запрос с заполнителями хранится в кеше.)

Пользовательское имя пользователя UPDATE =? и пароль =? WHERE id =?

  1. Вышеуказанный запрос будет разобран, скомпилирован с заполнителями в качестве специального лечения, оптимизирован и получен Cached. Запрос на этом этапе уже скомпилирован и преобразован в понятном для машины формате. Таким образом, мы можем сказать, что Query, хранящийся в кеше, предварительно компилируется, и только заполнители должны быть заменены данными, предоставленными пользователем.

  2. Теперь во время выполнения, когда предоставляются данные, предоставленные пользователем, Pre-Compiled Query выбирается из кэша, а замещающие заменяются данными, предоставленными пользователем.

PrepareStatementWorking

(Помните, что после того, как владельцы мест заменяются пользовательскими данными, окончательный запрос еще не компилируется/интерпретируется, а механизм SQL Server обрабатывает данные пользователя как чистые данные, а не SQL, которые необходимо проанализировать или скомпилировать снова, то есть красоту PreparedStatement. )

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

Примечание. Это этап компиляции после фазы анализа, который понимает/интерпретирует структуру запроса и дает осмысленное поведение. В случае PreparedStatement запрос скомпилируется только один раз, и кешированный скомпилированный запрос все время подбирается для замены пользовательских данных и выполнения.

Из-за одной функции компиляции в PreparedStatement она не содержит атаки SQL Injection.

Подробное объяснение можно найти здесь: http://javabypatel.blogspot.in/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html

+67
источник

SQL, используемый в PreparedStatement, предварительно скомпилирован в драйвере. С этого момента параметры отправляются драйверу как значения литерального значения, а не исполняемые части SQL; таким образом, SQL не может быть введен с использованием параметра. Другим полезным побочным эффектом PreparedStatements (предварительная компиляция + отправка только параметров) является повышенная производительность при выполнении оператора несколько раз даже с разными значениями параметров (при условии, что драйвер поддерживает PreparedStatements), поскольку драйверу не нужно выполнять разбор и компиляцию SQL каждый время изменения параметров.

+25
источник

I Угадать будет строка. Но входные параметры будут отправлены в базу данных, и соответствующие соответствующие приведения/преобразования будут применены до создания фактического оператора SQL.

Чтобы дать вам пример, он может попробовать и посмотреть, работает ли CAST/Conversion.
Если он работает, он может создать из него окончательный вывод.

   SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))

Попробуйте пример с оператором SQL, принимающим числовой параметр.
Теперь попробуйте передать строковую переменную (с числовым содержимым, допустимым как числовой параметр). Возникает ли ошибка?

Теперь попробуйте передать строковую переменную (с содержимым, которое неприемлемо как числовой параметр). Посмотрите, что произойдет?

+3
источник

Подготовленный оператор более безопасен. Он преобразует параметр в указанный тип.

Например, stmt.setString(1, user); преобразует параметр user в строку.

Предположим, что параметр содержит строку SQL, содержащую исполняемую команду: использование подготовленного оператора не позволит этого.

Он добавляет метахарактер (преобразование a.k.a.) к этому.

Это делает его более безопасным.

+3
источник

Как объясняется в этом сообщении, PreparedStatement не поможет вам, если вы все еще конкатенируете Strings.

Например, один из злоумышленников-злоумышленников может сделать следующее:

  • вызовите функцию сна, чтобы все соединения с базой данных были заняты, поэтому ваше приложение недоступно
  • извлечение конфиденциальных данных из БД
  • обход аутентификации пользователя

Не только SQL, но даже JPQL или HQL могут быть скомпрометированы, если вы не используете параметры привязки.

В нижней строке вы никогда не должны использовать конкатенацию строк при создании операторов SQL. Для этого используйте специальный API:

+1
источник

SQL-инъекция: когда пользователь имеет возможность ввести то, что может быть частью оператора sql

Например:

String query = "INSERT INTO students VALUES ('" + user + "')"

когда пользователь вводит "Роберт", студенты DROP TABLE, - "как вход, он вызывает SQL-инъекцию

Как подготовленное выражение предотвращает это?

Строковый запрос = "INSERT INTO students VALUES ('" + ": name" + "')"

parameters.addValue("имя", пользователь);

=> когда пользователь снова вводит "Роберт", студенты DROP TABLE, - "входная строка предварительно скомпилирована в драйвере как литералы, и я предполагаю, что она может быть выполнена как:

CAST ( 'Роберт); Студенты DROP TABLE; - 'AS varchar (30))

Поэтому в конце строка будет буквально вставлена как имя в таблицу.

http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/

+1
источник

PreparedStatement:

1) Предварительная компиляция и кэширование базы данных SQL-оператора приводит к более быстрому выполнению и возможности повторного использования одного и того же оператора SQL в пакетах.

2) Автоматическое предотвращение атак SQL-инъекций путем встроенного экранирования кавычек и других специальных символов. Обратите внимание, что для установки значения необходимо использовать любой из методов PreparedStatement setXxx().

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос