Как PreparedStatement избежать или предотвратить SQL-инъекции?

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

9 ответов


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

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


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

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

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


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

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

всякий раз, когда SQL server engine получает запрос, он должен пройти через этапы ниже,

Query Execution Phases

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

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

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

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

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


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


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

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

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

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

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


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

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

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

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

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


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

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

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

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


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

например:

String query = " вставить в значения студентов ('"+user +"‘)"

при вводе пользователем "Robert’); -" в качестве ввода он вызывает SQL-инъекцию

Как подготовленное заявление этому мешает?

String query = "вставить в значения студентов (‘" + ": name" + "‘)"

параметры.addValue("наименование", пользователь);

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

CAST ('Robert’); падение таблицы студентов; – ‘ as varchar(30))

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

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


PreparedStatement:

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

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