[JAVA] Parlez des mérites des variables de liaison de base de données (② Mérite: Prévention de l'injection SQL)

2018/7/14 Révision complète

====================================================================

** 0. Introduction **

Dernier message Alors, quelles sont les variables de liaison de base de données? Je l'ai expliqué, mais cette fois, je voudrais vous dire le premier avantage de l'utiliser. En un mot, cela peut empêcher l'injection SQL (* 1).

** 1. Cas préalable **

Je reviendrai sur le tableau présenté dans le post précédent.

id passwrod username email
22222 password2 Ruffy [email protected]
55555 password5 Sakuragi Hanamichi [email protected]
11111 password1 Momotaro Ken [email protected]
33333 password3 Chatouiller [email protected]

Les informations sont obtenues en spécifiant l'ID utilisateur et le mot de passe de cette table, mais l'ID connaît "11111", mais placez "'OU' A '=' A" à la place de YYY dans MOT DE PASSE. Prenons le cas de l'émission de SQL. SQL ressemble à ceci.

SELECT * FROM USERTABLE WHERE ID=11111 AND PASSWORD='' OR 'A' = 'A';

Voyons quel sera le résultat avec et sans la variable bind.

** 2. Si vous n'utilisez pas de variables de liaison **

Si vous n'utilisez pas de variables de liaison, le code SQL ci-dessus sera interprété comme suit:

Suivant 1. Ou 2. Si l'une des conditions est remplie, toutes les informations sont extraites de USERTABLE.
Condition 1.
USERID est 11111 et PASSWORD est vide (correspond à "ID = 11111 AND PASSWORD = ''" dans la clause WHERE).


Condition 2.
La valeur "A" et la valeur "A" sont égales (correspondant à "'A' = 'A'" dans la clause WHERE).

Il n'y a pas d'informations utilisateur dans ce tableau avec l'ID 11111 et le MOT DE PASSE vide, donc première condition 1. Ne s'applique pas à. Deuxièmement, la condition 2 s'applique à tout le monde. En passant, modifiez / ajoutez le code Java introduit dans Last Post comme suit, et lancez SQL.

System.out.println("***** main method start *****");
・ ・ ・(Détails omis)・ ・ ・
//Préparez une déclaration.
statement = connection.createStatement();
//Déclarez SQL. Configurez SQL avec un ID et un mot de passe variables.
String sql = "select * from app.usertable where id = 11111 and password = '' OR 'A' = 'A'";
//Obtenez le résultat.
resultSet = statement.executeQuery(sql);
//Affichez le résultat.
while(resultSet.next()) {
                System.out.println("ID: " + resultSet.getInt(1));
                System.out.println("Nom complet:" + resultSet.getString(3));
                System.out.println("adresse mail:" + resultSet.getString(4));
}

・ ・ ・(Détails omis)・ ・ ・
System.out.println("***** main method end *****");

Le résultat est le suivant. J'ai essayé un SGBD avec Derby (JavaDB) et MySQL et j'ai obtenu le même résultat.

***** main method start *****
ID: 22222
Nom: Ruffy
Adresse e-mail: [email protected]
ID: 55555
Nom: Sakuragi Hanamichi
Adresse e-mail: [email protected]
ID: 11111
Nom: Momotaro Ken
Adresse e-mail: [email protected]
ID: 33333
Nom: Kinni chatouiller
Adresse e-mail: [email protected]
***** main method end *****

Oups! ?? J'ai pu récupérer toutes les informations du tableau. Normalement, vous devez entrer les valeurs correctes pour ID et PASSWORD pour obtenir les informations correspondantes de USERTABLE, mais en entrant "'OR' A '=' A" pour PASSWORD, USERTABLE est défini illégalement. Vous pourrez récupérer toutes les informations. Voici un exemple d'injection SQL.

** 3. Lors de l'utilisation de variables de liaison **

Alors, que se passe-t-il lorsque vous utilisez des variables de liaison pour ce SQL? Le code Java introduit dans Last Post est légèrement modifié comme suit.

System.out.println("***** main method start *****");
・ ・ ・(Détails omis)・ ・ ・
//Déclarez SQL. Pour l'ID de colonne et le mot de passe,?En insérant ", celles-ci sont déclarées comme étant des variables de liaison.
String sql = "select * from app.usertable where id = ? and password = ?";
//Préparez un PreparedStatement pour émettre le SQL qui stocke les variables de liaison.
preparedStatement = connection.prepareStatement(sql);
//Attribuez une valeur à id. Ce "1" fait référence à la première variable de liaison id.
preparedStatement.setInt(1, 11111);
//Attribuez une valeur au mot de passe. Ce «2» fait référence au deuxième mot de passe de la variable de liaison.
preparedStatement.setString(2, "'' OR 'A' = 'A'");
//Obtenez le résultat.
resultSet = preparedStatement.executeQuery();
//Affichez le résultat.
while(resultSet.next()) {
                System.out.println("ID: " + resultSet.getInt(1));
                System.out.println("Nom complet:" + resultSet.getString(3));
                System.out.println("adresse mail:" + resultSet.getString(4));
}

・ ・ ・(Détails omis)・ ・ ・
System.out.println("***** main method end *****");

L'exécution du code ci-dessus émettra le SQL, mais le résultat sera: J'ai également essayé un SGBD avec Derby (JavaDB) et MySQL, et les résultats étaient les mêmes.

***** main method start *****
***** main method end *****

Oh? Rien n'est affiché? Qu'est-ce qui s'est passé?

Le flux suivant montre ce qui se passe lorsque SQL avec des variables de liaison est émis.

(1) La valeur de la variable de liaison et le SQL qui l'exclut sont envoyés au SGBD séparément. (2) La valeur de la variable de liaison est interprétée avant d'être fusionnée dans SQL, et "'" est échappé. En d'autres termes, puisque "'" est interprété comme le caractère "'", il est converti en "''" avec deux guillemets simples. (3) La valeur de la variable de liaison traitée dans (2) et SQL est fusionnée et exécutée.

バインド変数SQLが発行されるイメージ.png

Le SQL exécuté dans ③ est SELECT * FROM USERTABLE WHERE ID=11111 AND PASSWORD=''' OR ''A'' = ''A'; Ce sera comme suit. Comment c'est? Vous pouvez voir qu'il est différent du SQL lorsqu'il a été attaqué par injection. C'est vrai. MOT DE PASSE est interprété comme "'' OU '' A '' =" A "". Un utilisateur avec un tel mot de passe n'existe pas dans USERTABLE, il ne sera donc pas possible de récupérer toutes les informations.

Ce qui précède est un exemple. Il existe également un moyen d'échapper non seulement à "'" mais aussi à ">" et "<", veuillez donc vous référer au manuel de la base de données, etc. (* 2).

** 4. Conclusion **

À propos, la prochaine fois à la fin de cette série, je voudrais parler du deuxième avantage des variables de liaison.

note de bas de page

(※1) Veuillez consulter l'URL suivante pour obtenir des explications sur l'injection SQL. https://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3

(※2) Cliquez ici pour Oracle Database. http://www.oracle.com/technetwork/jp/database/articles/pickup/index-1622026-ja.html

(※3) J'ai également fait référence à l'URL suivante lors de la création de cet article.

Organisation de promotion du traitement de l'information IPA "Comment appeler Secure SQL" http://www.ipa.go.jp/files/000017320.pdf

Hatena Diary [Security] Escape dans Oracle http://d.hatena.ne.jp/teracc/20071230

Recommended Posts

Parlez des mérites des variables de liaison de base de données (② Mérite: Prévention de l'injection SQL)
Parler des mérites des variables de liaison de base de données ((1) Introduction)
[Sortie] À propos de la base de données
[Java] J'ai réfléchi aux mérites et aux utilisations de "interface"
À propos de la gestion de Null
À propos de la description de Docker-compose.yml
Parlons de l'expérience passagère de Java SE 8 Programmer II
[Rails] Parlez de prêter attention à la valeur de retour de l'endroit