Explication détaillée du cas de problème d'injection JDBC SQL (version simple et facile à comprendre)

Qu'est-ce que l'injection SQL?
L'injection SQL signifie que l'application Web ne juge pas la légalité des données entrées par l'utilisateur ou que le filtrage n'est pas strict. L'attaquant peut ajouter des instructions SQL supplémentaires à la fin de l'instruction de requête définie dans l'application Web à l'insu de l'administrateur. Dans le cas d'opérations illégales, tromper le serveur de base de données pour effectuer toute requête non autorisée, afin d'obtenir en outre les informations de données correspondantes.
Pour le dire simplement,
lorsque les données entrées par l'utilisateur ont des mots-clés ou une syntaxe SQL et participent à la compilation de l'instruction SQL, le résultat de la condition après la compilation de l'instruction SQL est vrai et le résultat correct est toujours obtenu. Appelée injection SQL


Cas où elle est venue tranquillement ...

Insérez la description de l'image ici


Créer une table

  • Créer une table utilisateur Utilisateur
    • id clé primaire, croissance automatique
    • le type de chaîne du nom d'utilisateur n'est pas vide
    • le type de chaîne de mot de passe n'est pas vide
    • type de chaîne de téléphone
  • Insérez 2 déclarations de test
#创建数据库
CREATE DATABASE temp CHARACTER SET utf8;
#使用该数据库
USE temp;
#创建用户表
CREATE TABLE user (
	id INT PRIMARY KEY auto_increment,
	username CHARACTER(20) NOT NULL,
	password CHARACTER(20) NOT NULL,
	phone CHARACTER(11)
) charset = utf8;
#初始化(插入)表中数据
INSERT INTO user (username, password, phone) VALUES ('ziph', '123456', '16688889999');
INSERT INTO user (username, password, phone) VALUES ('zhangsan', '123456', '16644445555');

Connectez-vous

  • Via la console, l'utilisateur entre le nom d'utilisateur et le mot de passe
  • Le nom d'utilisateur et le mot de passe saisis par l'utilisateur sont utilisés comme paramètres pour écrire une instruction SQL de requête.
  • Si un utilisateur est interrogé, l'utilisateur existe, invitant à une connexion réussie, sinon, invitant à l'échec!

Code JDBC simple:

import java.sql.*;
import java.util.Scanner;

public class TestLogin {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String userName = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();

        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.获取连接对象,连接数据库
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/temp?useUnicode=true&characterEncoding=utf8", "root", "123456");
        //3.创建执行SQL语句的对象
        Statement statement = connection.createStatement();
        //4.编写SQL语句,并执行SQL语句
        String sql = "select * from user where username = '" + userName + "' and password = '" + password + "'";
        ResultSet resultSet = statement.executeQuery(sql);
        //5.处理结果
        if (resultSet.next()) {//通过参数,查到一行数据,就提示用户的登陆成功!
            System.out.println("登录成功!");
        } else {
            System.out.println("登录失败!");
        }
        //6.释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}

La version simple et facile à comprendre des tests d'injection SQL est la suivante:

Nom d'utilisateur, mot de passe (pas dans la base de données de noms d'utilisateurs, le mot de passe est entré de manière négligente) J'ai entré le contenu sur la console, mais la connexion a réussi! Que se passe-t-il? Alors jetons un coup d'œil à nouveau, voir l'image ci-dessous!
Insérez la description de l'image ici


Insérez la description de l'image ici
Jetez un œil à la partie en surbrillance. Cette partie est l'instruction exécutée par SQL, et userName et mot de passe sont les informations entrées dans notre console (également impliquées dans l'exécution des instructions SQL). Mais lorsque vous entrez la chaîne lalala, cela ne pose aucun problème, mais lorsque vous saisissez à nouveau ', lorsque SQL est exécuté, il pensera que' est la fin de userName. Parallèlement à cela, j'ai entré le contenu derrière ou 1 = 1 pour participer à l'exécution SQL au lieu du mot de passe entré. Ici, j'explique, car 1 = 1, la valeur par défaut est vraie, donc le mot de passe est passé! ; Elle est considérée comme la marque de fin de l'instruction SQL, suivie d'un # tout commenté après le mot de passe, etc. Lorsque resultSet.next () juge, parce que son résultat retourne le type booléen, l'injection SQL ci-dessus renvoie naturellement un vrai. A franchi avec succès les limites du compte et du mot de passe, et la connexion a réussi! C'est l'injection SQL! Tout le monde peut le comprendre! Continuons donc à lire la déclaration suivante! Cette instruction est l'instruction exécutée par SQL après injection SQL:

sql = "select * from user where username='xxx' or 1=1;#'and password ='123456'";

Comment éviter les problèmes d'injection SQL?

L'instruction SQL est compilée après que l'utilisateur a entré les données, puis compilée dans les instructions SQL après l'intégration. Ainsi, afin d'éviter le problème de l'injection SQL, l'instruction SQL a été compilée avant que l'utilisateur n'entre les données, et l'instruction SQL a été compilée en une instruction SQL complète, puis les données sont remplies. Chaîne longue, empêcher l'injection), voulez savoir comment résoudre, puis continuez à regarder les points clés suivants, n'oubliez pas d'être le point clé!


Application de PreparedStatement

L'interface PreparedStatement hérite de l'interface Statement. Il n'y a aucune différence dans la méthode d'exécution des instructions SQL!

Rôle:

  • 1. Instructions SQL précompilées, haute efficacité!
  • 2. Sécurité, évitez l'injection SQL
  • 3. Peut remplir dynamiquement des données et exécuter plusieurs instructions SQL homogènes

Marqueur de paramètre

//1.预编译SQL语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
  • Remarque: Lorsque le PreparedStatement est appliqué, les paramètres de la chaîne SQL sont tous représentés par le symbole?, Qui est appelé le marqueur de paramètre. Avant d'exécuter l'instruction SQL, affectez des valeurs à chacune? Paramètre

Liaison de paramètres dynamique

pstmt.setXxx (indice, valeur); l' indice de paramètre commence à 1 et lie la valeur de l'indice d'espace réservé spécifié

//2.为占位符下标赋值
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);

Résoudre ce problème d'injection SQL de test

import java.sql.*;
import java.util.Scanner;

public class TestSafeLogin {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();

        //1.注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.获取连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/temp?useUnicode=true&characterEncoding=utf8","root", "123456");
        //3.创建执行sql语句的对象
        String sql = "select * from user where username = ? and password = ?";
        //预编译SQL语句————提前把SQL语句编译为字符串,其中用到了转义字符防止个别符号注入SQL
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        /**
         * 查看预编译后的SQL语句字符串
         * 此查看不计为jdbc的开发步骤中
         */
        System.out.println(preparedStatement);

        //为占位符下标赋值
        preparedStatement.setString(1, username);
        preparedStatement.setString(2, password);

        /**
         * 查看赋值后SQL语句的字符串
         * 此查看不计为jdbc的开发步骤中
         */
        System.out.println(preparedStatement);

        //4.执行SQL语句————此时executeQuery()不需要在传入参数
        ResultSet resultSet = preparedStatement.executeQuery();
        //5.处理结果
        if (resultSet.next()) {//通过参数,查到一行数据,提示用户登录成功!
            System.out.println("登陆成功!");
        } else {
            System.out.println("登录失败!");
        }
        //6.释放资源
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

Résumé

Entrez le nom d'utilisateur et le mot de passe de la question d'injection SQL et obtenez le résultat suivant!

Affichez le résultat de la chaîne d'instruction SQL précompilée: com.mysql.jdbc.JDBC4PreparedStatement@4b9af9a9: sélectionnez * à partir de l'utilisateur où le nom d'utilisateur = ** NON SPÉCIFIÉ ** et le mot de passe = ** NON SPÉCIFIÉ **

Affichez le résultat de la chaîne de l'instruction SQL après l'affectation: com.mysql.jdbc.JDBC4PreparedStatement@4b9af9a9: sélectionnez * à partir de l'utilisateur où username = 'lalal' ou 1 = 1; # 'et password =' ​​asdsad '

Résultat final: la connexion a échoué!

Remarque: Nous pouvons voir que «lalal behind» a été ajouté avec un caractère d'échappement, et ou 1 = 1; # suivi de l'indicateur de fin du nom d'utilisateur qui doit être ajouté dans l'instruction SQL ».

Publié 155 articles originaux · loué 337 · 90 000 vues +

Je suppose que tu aimes

Origine blog.csdn.net/weixin_44170221/article/details/105259177
conseillé
Classement