Вопрос-ответ

How does a PreparedStatement avoid or prevent SQL injection?

Как PreparedStatement избегает или предотвращает внедрение SQL?

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

Переведено автоматически
Ответ 1

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

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();

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

Robert'); DROP TABLE students; --

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

Ответ 2

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

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

Всякий раз, когда механизм SQL Server получает запрос, он должен пройти следующие этапы,

Этапы выполнения запроса


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


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


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


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


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


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


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


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



    1. Этап синтаксического анализа и нормализации

    2. Этап компиляции

    3. План оптимизации запросов

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



ОБНОВИТЬ имя пользователя, установленное пользователем =? и пароль =? ГДЕ id =?



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


  2. Теперь во время выполнения, когда поступают предоставленные пользователем данные, предварительно скомпилированный запрос извлекается из кэша, а заполнители заменяются данными, предоставленными пользователем.


PrepareStatementWorking

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

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

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

Благодаря функции одноразовой компиляции PreparedStatement, он свободен от SQL-инъекционной атаки.

Подробное объяснение с примером можно получить здесь: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html

Ответ 3

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

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

Ответ 4

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

java sql jdbc