Ответ 1
Вы определенно хотите использовать PreparedStatement s. Они удобны. Вот пример .
Может ли кто-нибудь указать мне хорошее руководство для начинающих по безопасному запуску SQL-запросов, сформированных частично из пользовательского ввода? Я использую Java, но руководство, ориентированное на язык, тоже прекрасное.
Желаемое поведение заключается в том, что если кто-то вводит в GUI что-то вроде
very nice;) DROP TABLE FOO;
База данных должна обрабатывать ее как литеральную строку и сохранять ее безопасно, не отбрасывая никаких таблиц.
Вы определенно хотите использовать PreparedStatement s. Они удобны. Вот пример .
Используйте PreparedStatement вместо Statement
Как правило, вы не должны создавать конкатенацию ввода запроса, но вместо этого используйте PreparedStatement.
Это позволяет указать, в каких местах вы будете устанавливать параметры внутри своего запроса, поэтому Java позаботится о том, чтобы санировать все входы для вас.
PreparedStatement? Да, конечно. Но я думаю, что есть еще один шаг: проверка ввода из пользовательского интерфейса и привязка к объектам до приближения к базе данных.
Я вижу, где привязка String в PreparedStatement может по-прежнему оставаться уязвимой для атаки SQL-инъекции:
String userInput = "Bob; DELETE FROM FOO";
String query = "SELECT * FROM FOO WHERE NAME = ?";
PreparedStatement ps = connection.prepareStatement(query);
ps.setString(1, userInput);
ps.executeQuery();
Я должен признать, что я сам не пробовал, но если это возможно, я бы сказал, что PreparedStatement необходим, но недостаточно. Валидация и привязка на стороне сервера являются ключевыми.
Я бы рекомендовал сделать это с помощью API-интерфейсов Spring.
Ваш пользовательский ввод фактически должен быть "Bob'; delete from foo; select '"
(или что-то вроде этого), поэтому неявные цитаты, добавленные подготовленным оператором, будут закрыты:
SELECT * FROM FOO WHERE NAME = 'Bob'; delete from foo; select ''
но если вы сделаете это, то подготовленный код оператора будет цитировать вашу цитату, чтобы вы получили фактический запрос
SELECT * FROM FOO WHERE NAME = 'Bob''; delete from foo; select '''
и ваше имя будет храниться как "Bob', delete from foo; select '"
вместо запуска нескольких запросов.