Безопасные запросы с PreparedStatement
Last updated: 9 мая 2025 г.Напрямую в запрос данные пользователя передавать нельзя! Это опасно. Пользователь может туда вставить любое sql выражение какое ему вздумается.
Это называется sql инъекцией. И в результате может, например, что-то изменить в базе или своровать данные.
PreparedStatement
– как Statement, только безопаснее. Он добавляет методы для управления входными параметрами от пользователя.
Продемонстрируем пример SQL инъекции.
Пример программы:
1import java.sql.*;
2
3public class PrStatement {
4 public static void main(String[] args)
5 throws ClassNotFoundException, SQLException {
6 Class.forName("com.mysql.cj.jdbc.Driver");
7 Connection connection =
8 DriverManager.getConnection(
9 "jdbc:mysql://localhost/storage",
10 "root", "07998MSD");
11 Statement statement = connection.createStatement();
12
13 //Положим переменная ниже это данные от
14 //пользователя например которые он ввел
15 //в текстовое поле на странице и которые
16 //в результате пришли сюда в программу.
17 //Эта переменная будет передаваться в sql запрос.
18 String userInpData = "‘LOTR’ or name=’Book1′;";
19
20 //Ниже в запрос передается переменная userInpData
21 ResultSet resultSet = statement.executeQuery(
22 "SELECT * FROM books where name="+ userInpData);
23 //вредный вариант очевидно не безопасен.
24 //Так как пользователь прислал сюда не просто
25 //название книги, например LOTR, а целую часть
26 //SQL запроса и в итоге то что прислал
27 //пользователь сложиться с тем что в методе
28 //executeQuery и выполниться запрос:
29 //SELECT * FROM books where name=’LOTR’ or name=’Book1′;.
30 //который выведет две книги, а не одну как было
31 //по задумке программистом.
32
33 System.out.println("\nBooks:");
34 while (resultSet.next()) {
35 int id = resultSet.getInt("id");
36 String name = resultSet.getString("name");
37
38 System.out.println("\n================\n");
39 System.out.println("id: " + id);
40 System.out.println("name: " + name);
41 }
42
43 System.out.println("Closing connection and "
44 +"releasing resources…");
45 resultSet.close();
46 statement.close();
47 connection.close();
48 }
49}
Вывод:

Видим, что произошла инъекция SQL запроса пользователем в SQL запрос, который в методе executeQuery. Таким образом, вывелось две книги вместо одной, как задумывал программист.
Теперь продемонстрируем пример с PreparedStatement
, который предотвращает SQL инъекции.
Пример программы:
1import java.sql.*;
2
3public class PrStatement {
4 public static void main(String[] args)
5 throws ClassNotFoundException, SQLException {
6 Class.forName("com.mysql.cj.jdbc.Driver");
7 Connection connection = DriverManager.getConnection(
8 "jdbc:mysql://localhost/storage",
9 "root", "07998MSD");
10
11 String userInpData = "‘LOTR’ or name=’Book1′;"
12
13 //Запрос теперь делаем с помощью PreparedStatement
14 PreparedStatement pstatement =
15 connection.prepareStatement(
16 "SELECT * FROM books where name = ?");
17
18 //В строке кода ниже первый параметр
19 //это порядковый номер вопросика
20 //в верхнем запросе, второй данные от пользователя,
21 //которые средствами PreparedStatement будут
22 //переданы в запрос на место этого вопросика
23 //уже безопасным образом.
24 pstatement.setString(1,userInpData);
25 //preparedstatement защищает нас от инъекций как
26 //бы пользователь не менял userInpData.
27 ResultSet presultSet = pstatement.executeQuery();
28
29 System.out.println("\nBooks:");
30 while (presultSet.next()) {
31 int id = presultSet.getInt("id");
32 String name = presultSet.getString("name");
33
34 System.out.println("\n——————–");
35 System.out.println("id: " + id);
36 System.out.println("name: " + name);
37 }
38
39 System.out.println("Closing connection and "
40 +"releasing resources…");
41 presultSet.close();
42 pstatement.close();
43 connection.close();
44 }
45}
Вывод:

Видим, что ничего не вывелось, то есть PreparedStatement
предотвратил инъекцию.
Следующие уроки
Использование хранимых процедур в Java
14
мин.
Что такое HTML и зачем он нужен
10
мин.
Ключевые теги HTML
9
мин.