Я знаю, что PreparedStatements избегает / предотвращает внедрение SQL. Как оно это делает? Будет ли окончательный запрос формы, созданный с использованием PreparedStatements, быть строкой или иначе?
Я знаю, что PreparedStatements избегает / предотвращает внедрение SQL. Как оно это делает? Будет ли окончательный запрос формы, созданный с использованием PreparedStatements, быть строкой или иначе?
Ответы:
Проблема с 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; --
Тогда в первую очередь вас закроют из шланга. Во втором случае вы будете в безопасности, и Little Bobby Tables будут зарегистрированы в вашей школе.
Чтобы понять, как PreparedStatement предотвращает SQL-инъекцию, нам необходимо понять этапы выполнения SQL-запроса.
1. Фаза компиляции. 2. Этап исполнения.
Всякий раз, когда механизм SQL-сервера получает запрос, он должен пройти следующие этапы:
Этап синтаксического анализа и нормализации: на этом этапе запрос проверяется на синтаксис и семантику. Он проверяет, существуют ли ссылки на таблицу и столбцы, используемые в запросе. У него также много других задач, но не будем вдаваться в подробности.
Этап компиляции: на этом этапе ключевые слова, используемые в запросе, например select, from, where и т. Д., Преобразуются в формат, понятный для машины. Это этап, на котором интерпретируется запрос и принимается решение о соответствующем действии. У него также много других задач, но не будем вдаваться в подробности.
План оптимизации запроса: на этом этапе создается дерево решений для поиска способов выполнения запроса. Он определяет количество способов, которыми может быть выполнен запрос, и стоимость, связанную с каждым способом выполнения запроса. Он выбирает лучший план для выполнения запроса.
Кэш: лучший план, выбранный в плане оптимизации запросов, сохраняется в кеше, поэтому всякий раз, когда в следующий раз поступает тот же запрос, ему не нужно снова проходить этапы 1, 2 и 3. Когда в следующий раз поступит запрос, он будет проверен непосредственно в кэше и оттуда будет взят для выполнения.
Этап выполнения: на
этом этапе выполняется предоставленный запрос, и данные возвращаются пользователю в виде ResultSet
объекта.
PreparedStatements не являются полными SQL-запросами и содержат заполнители, которые во время выполнения заменяются фактическими данными, предоставленными пользователем.
Всякий раз, когда какой-либо PreparedStatment, содержащий заполнители, передается в механизм SQL Server, он проходит следующие этапы
ОБНОВЛЕНИЕ пользовательского набора username =? и пароль =? ГДЕ id =?
Вышеупомянутый запрос будет проанализирован, скомпилирован с заполнителями в качестве специальной обработки, оптимизирован и будет кэширован. Запрос на этом этапе уже скомпилирован и преобразован в понятный для машины формат. Таким образом, мы можем сказать, что запрос, хранящийся в кеше, предварительно скомпилирован, и только заполнители необходимо заменить данными, предоставленными пользователем.
Теперь во время выполнения, когда поступают данные, предоставленные пользователем, предварительно скомпилированный запрос извлекается из кеша, а заполнители заменяются данными, предоставленными пользователем.
(Помните, что после того, как заполнители заменяются пользовательскими данными, окончательный запрос не компилируется / интерпретируется снова, и механизм SQL Server обрабатывает пользовательские данные как чистые данные, а не SQL, который необходимо анализировать или компилировать снова; в этом прелесть PreparedStatement. )
Если запрос не должен снова проходить этап компиляции, то любые данные, замененные на заполнителях, обрабатываются как чистые данные и не имеют значения для механизма SQL Server, и он непосредственно выполняет запрос.
Примечание. Это фаза компиляции после фазы синтаксического анализа, которая понимает / интерпретирует структуру запроса и придает ей осмысленное поведение. В случае PreparedStatement запрос компилируется только один раз, а кэшированный скомпилированный запрос всегда выбирается для замены пользовательских данных и выполнения.
Благодаря одноразовой функции компиляции PreparedStatement, он свободен от атак SQL Injection.
Вы можете получить подробное объяснение с примером здесь: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
SQL, используемый в PreparedStatement, предварительно компилируется в драйвере. С этого момента параметры отправляются драйверу как буквальные значения, а не как исполняемые части SQL; таким образом, нельзя ввести SQL с помощью параметра. Еще один полезный побочный эффект PreparedStatements (предварительная компиляция + отправка только параметров) - повышение производительности при многократном выполнении оператора даже с разными значениями параметров (при условии, что драйвер поддерживает PreparedStatements), поскольку драйверу не нужно выполнять синтаксический анализ и компиляцию SQL каждый раз. время изменения параметров.
Я думаю, это будет веревка. Но входные параметры будут отправлены в базу данных, и перед созданием фактического оператора SQL будут применены соответствующие приведения / преобразования.
Например, он может попытаться проверить, работает ли CAST / Conversion.
Если это сработает, на его основе можно будет сделать окончательное утверждение.
SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))
Попробуйте пример с оператором SQL, принимающим числовой параметр.
Теперь попробуйте передать строковую переменную (с числовым содержанием, приемлемым в качестве числового параметра). Возникает ли ошибка?
Теперь попробуйте передать строковую переменную (с содержанием, неприемлемым в качестве числового параметра). Смотрите, что происходит?
Подготовленная выписка более безопасна. Он преобразует параметр в указанный тип.
Например stmt.setString(1, user);
, преобразует user
параметр в строку.
Предположим, что параметр содержит строку SQL, содержащую исполняемую команду : использование подготовленного оператора не позволит этого.
Он добавляет к этому метасимвол (он же автоматическое преобразование).
Это делает его более безопасным.
SQL-инъекция: когда у пользователя есть возможность ввести что-то, что может быть частью оператора sql
Например:
Строковый запрос = «ВСТАВИТЬ ЗНАЧЕНИЯ студентов ('» + пользователь + «')»
когда пользователь вводит «Роберт»); DROP TABLE студенты; - ”в качестве входных данных вызывает SQL-инъекцию.
Как подготовленное заявление предотвращает это?
Строковый запрос = «ВСТАВИТЬ ЗНАЧЕНИЯ учеников ('» + «: имя» + «')»
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/
CAST(‘Robert’);
из CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
сломалась бы, тогда она продолжила бы падение таблицы, если бы это было так. Он останавливает инъекцию, поэтому я считаю, что этот пример недостаточно полный, чтобы объяснить сценарий.
Подготовленное заявление:
1) Предварительная компиляция и кэширование оператора SQL на стороне БД приводит к общему более быстрому выполнению и возможности многократно использовать один и тот же оператор SQL в пакетах.
2) Автоматическое предотвращение атак SQL-инъекций путем экранирования кавычек и других специальных символов. Обратите внимание, что для этого необходимо использовать любой из методов PreparedStatement setXxx () для установки значения.
Как объясняется в этом посте , само по PreparedStatement
себе не поможет, если вы все еще объединяете строки.
Например, один злоумышленник по-прежнему может делать следующее:
Не только SQL, но даже JPQL или HQL могут быть скомпрометированы, если вы не используете параметры привязки.
В итоге, вы никогда не должны использовать конкатенацию строк при построении операторов SQL. Для этого используйте специальный API:
В подготовленных отчетах пользователь вынужден вводить данные в качестве параметров. Если пользователь вводит некоторые уязвимые операторы, такие как DROP TABLE или SELECT * FROM USERS, данные не будут затронуты, поскольку они будут рассматриваться как параметры оператора SQL.