JDBC SQLインジェクション問題のケースの詳細な説明(シンプルで理解しやすいバージョン)

SQLインジェクションとは何ですか?
SQLインジェクションとは、Webアプリケーションがユーザーによるデータ入力の合法性を判断しないか、フィルタリングが厳密でないことを意味します。攻撃者は、管理者の知らないうちに、Webアプリケーションで定義されたクエリステートメントの最後にSQLステートメントを追加できます。不正な操作の場合、データベースサーバーを欺いて、不正なクエリを実行し、対応するデータ情報をさらに取得します。
簡単に言うと、
ユーザーが入力したデータにSQLキーワードまたは構文があり、SQLステートメントのコンパイルに参加している場合、SQLステートメントのコンパイル後の条件結果はtrueであり、常に正しい結果が得られます。呼ばれるSQLインジェクション


彼女が静かにやってきた件...

ここに画像の説明を挿入


テーブルを作成

  • ユーザーテーブルユーザーを作成する
    • id主キー、自動拡張
    • ユーザー名の文字列タイプが空ではありません
    • パスワード文字列タイプが空ではありません
    • 電話の文字列タイプ
  • 2つのテスト文を挿入する
#创建数据库
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');

ログイン

  • ユーザーはコンソールからユーザー名とパスワードを入力します
  • ユーザーが入力したユーザー名とパスワードは、クエリSQLステートメントを書き込むためのパラメーターとして使用されます。
  • ユーザーが照会された場合、ユーザーは存在し、ログインの成功を要求します。それ以外の場合は、失敗を要求します。

単純なJDBCコード:

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();
    }
}

SQLインジェクションテストのシンプルで理解しやすいバージョンは次のとおりです。

ユーザー名、パスワード(ユーザー名データベースではなく、パスワードは何気なく入力されています)コンソールにコンテンツを入力しましたが、ログインは成功しました!何が起こっているのですか?それではもう一度見てみましょう。下の写真を見てください!
ここに画像の説明を挿入


ここに画像の説明を挿入
強調表示された部分を見てください。この部分はSQLによって実行されるステートメントであり、userNameとpasswordはコンソールに入力された情報です(SQLステートメントの実行にも関与します)。しかし、lalala文字列を入力しても問題はありませんが、 'を再入力すると、SQLが実行されるときに、'がuserNameの終わりであると見なされます。これに加えて、入力したパスワードの代わりに、SQL実行に参加するために1または1の後ろにコンテンツを入力しました。ここで説明します。1= 1なので、デフォルトはtrueなので、パスワードが渡されます。;これは、SQLステートメントの終了マークと見なされ、その後に#が続くと、パスワードの後に​​すべてがコメント化されます。結果セットがブール型を返すため、resultSet.next()が判断すると、上記のSQLインジェクションは当然trueを返します。アカウントとパスワードの境界を正常に超え、ログインは成功しました!これはSQLインジェクションです。誰でも理解できる!それでは、次のステートメントを読み続けましょう!このステートメントは、SQLインジェクション後にSQLによって実行されるステートメントです。

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

SQLインジェクションの問題を回避する方法

SQLステートメントは、ユーザーがデータを入力した後にコンパイルされ、統合後にSQLステートメントにコンパイルされます。したがって、SQLインジェクションの問題を回避するために、ユーザーがデータを入力する前にSQLステートメントがコンパイルされ、SQLステートメントが完全なSQLステートメントにコンパイルされ、データが入力されます(コンソールに入力した後、SQLステートメントを行に事前にコンパイルする必要があります)。長い文字列、注入を防ぐ)、解決方法を知りたい場合は、次の重要なポイントを引き続き確認し、重要なポイントであることを忘れないでください!


PreparedStatementの適用

PreparedStatementインターフェースはStatementインターフェースを継承します。SQL文の実行方法に違いはありません!

役割:

  • 1.コンパイル済みSQLステートメント、高効率!
  • 2.セキュリティ、SQLインジェクションを回避する
  • 3.データを動的に入力し、複数の同種SQLステートメントを実行できます

パラメータマーカー

//1.预编译SQL语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
  • 注:PreparedStatementが適用されると、SQL文字列のパラメーターはすべて、パラメーターマーカーと呼ばれる?記号で表されます。SQLステートメントを実行する前に、それぞれに値を割り当てますか?パラメータ

動的パラメーターのバインド

pstmt.setXxx(添え字、値);パラメーター添え字は1から始まり、値を指定されたプレースホルダー添え字にバインドします

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

このテストSQLインジェクション問題を解決する

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();
    }
}

まとめ

SQLインジェクションの質問のユーザー名とパスワードを入力すると、次の結果が得られます。

プリコンパイルされたSQLステートメント文字列の結果を表示します。com.mysql.jdbc.JDBC4PreparedStatement@ 4b9af9a9:select * from user where username = ** NOT SPECIFIED ** and password = ** NOT SPECIFIED **

割り当て後のSQLステートメントの文字列結果を表示します: com.mysql.jdbc.JDBC4PreparedStatement@4b9af9a9:select * from user where username = 'lalal' or 1 = 1;# 'and password =' asdsad '

最終結果:ログインに失敗しました!

注:「ララルビハインド」がエスケープ文字で追加されていること、または1 = 1;#の後にSQLステートメントに追加する必要があるユーザー名の終了フラグが続くことがわかります。

公開された155元の記事 ウォンの賞賛337 ・は 90000 +を見て

おすすめ

転載: blog.csdn.net/weixin_44170221/article/details/105259177