Ось SQL для налаштування прикладу:
CREATE TABLE employee(name varchar, paymentType varchar, amount bigint);
INSERT INTO employee VALUES('Aaron', 'salary', 100);
INSERT INTO employee VALUES('Aaron', 'bonus', 50);
INSERT INTO employee VALUES('Bob', 'salary', 50);
INSERT INTO employee VALUES('Bob', 'bonus', 0);
Клас Inject вразливий до ін'єкції SQL. Запит динамічно вставляється разом із введенням користувача. Завданням запиту було показати інформацію про Боба. Або заробітна плата, або бонус, залежно від даних користувачів. Але зловмисний користувач маніпулює вхідним пошкодженням запиту, встановлюючи еквівалент "або істинного" до пункту "де", щоб повернути все, включаючи інформацію про Аарона, яка повинна була бути прихованою.
import java.sql.*;
public class Inject {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/postgres?user=user&password=pwd";
Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='" + args[0] + "'";
System.out.println(sql);
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
}
}
}
Виконуючи це, перший випадок із звичайним використанням, а другий із шкідливою ін'єкцією:
c:\temp>java Inject salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary'
salary 50
c:\temp>java Inject "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary' OR 'a'!='b'
salary 100
bonus 50
salary 50
bonus 0
Не слід будувати ваші оператори SQL із строковим об'єднанням введення користувача. Він не тільки вразливий до ін'єкцій, але він також має наслідки кешування на сервері (заява змінюється, тому менша ймовірність потрапляння кеша операторів SQL, тоді як прив'язуючий приклад завжди виконує той самий оператор).
Ось приклад зв'язування, щоб уникнути подібного роду ін'єкцій:
import java.sql.*;
public class Bind {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/postgres?user=postgres&password=postgres";
Connection conn = DriverManager.getConnection(url);
String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?";
System.out.println(sql);
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, args[0]);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
}
}
}
Запустивши це з тим же входом, що і в попередньому прикладі, показано, що зловмисний код не працює, оскільки немає PaymentType, що відповідає цій рядку:
c:\temp>java Bind salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
salary 50
c:\temp>java Bind "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?