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ステートメントに追加する必要があるユーザー名の終了フラグが続くことがわかります。