SQLインジェクションの例とその解決方法
前文
SQLインジェクションとは、Webアプリケーションがユーザーの入力データの正当性を判断していない、または厳密なフィルタリングを行っていないため、攻撃者がWebアプリケーションであらかじめ定義したクエリ文の末尾にSQL文を追加して管理者の知らないところで不正操作を実現し、データベースサーバーを騙して不正な任意のクエリを実行させ、さらに該当するデータ情報を取得する目的を達成することを意味します。
1. SQLインジェクションの例
コンソールでユーザー名とパスワードを入力し、Statementの文字列連結でログインさせるというSQLインジェクションのケースをシミュレートしています。
1.1 データベースにユーザーテーブルとデータを最初に作成する
-- Create a table of users
CREATE TABLE `users` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(20),
`password` VARCHAR(50),
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- Insert data
INSERT INTO users(username,`password`) VALUES('Zhang Fei','123321'),('Zhao Yun','qazxsw'),('Zhuge Liang','123Qwe');
INSERT INTO users(username,`password`) VALUES('Cao Cao','741258'),('Liu Bei','plmokn'),('Sun Quan','! @#$%^');
-- View data
SELECT * FROM users;
1.2 ログインプログラムを作成する
package com.study.task0201;
import java.sql.*;
import java.util.Scanner;
public class TestSQLIn {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(url,"root","123456");
// System.out.println(conn);
// Get the statement execution platform object Statement
Statement smt = conn.createStatement();
Scanner sc = new Scanner(System.in);
System.out.println("Please enter the user name: ");
String userName = sc.nextLine();
System.out.println("Please enter the password: ");
String password = sc.nextLine();
String sql = "select * from users where username = '" + userName + "' and password = '" + password +"'"; //print out the SQL
System.out.println(sql);
ResultSet resultSet = smt.executeQuery(sql);
if(resultSet.next()){
System.out.println("Login successful!!! ");
}else{
System.out.println("Username or password error, please re-enter!!! ");
}
resultSet.close();
smt.close();
conn.close();
}
}
1.3 通常ログイン
正しいユーザー名とパスワードを入力すると、"Login successful"が表示されます。
1.4 ログイン失敗
ユーザー名またはパスワードを間違って入力した場合、「ユーザー名またはパスワードが間違っています、再入力してください"」が表示されます。
1.5 SQLインジェクションのシミュレーション
スプライスされた文字列は、定数条件として or '1'='1' を持つので、前のユーザとパスワードが存在しなくても、すべてのレコードが取得され、 "Login successful" と表示されます。
1.6 SQL構文エラー報告
スプライシングでは、SQL構文エラーなどのエラーも発生します、例えば
2. 解決方法
ステートメント方式では、文字列のスプライシングによって元のSQLの真意を変えることができるため、SQLインジェクションの危険性があります。SQLインジェクションを解決するには、Statementの代わりに前処理オブジェクトであるPreparedStatementを使用して処理することができます。
2.1 プロシージャ
import java.sql.*;
import java.util.Scanner;
public class TestSQLIn {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=UTF-8";
Connection conn = DriverManager.getConnection(url,"root","123456");
// System.out.println(conn);
// Get the statement execution platform object Statement
// Statement smt = conn.createStatement();
Scanner sc = new Scanner(System.in);
System.out.println("Please enter the user name: ");
String userName = sc.nextLine();
System.out.println("Please enter the password: ");
String password = sc.nextLine();
String sql = "select * from users where username = ? and password = ? ";
// System.out.println(sql);
// ResultSet resultSet = smt.executeQuery(sql);
PreparedStatement preparedStatement = conn.preparedStatement(sql);
preparedStatement.setString(1,userName);
preparedStatement.setString(2,password);
ResultSet resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
System.out.println("Login successful!!! ");
}else{
System.out.println("Username or password error, please re-enter!!! ");
}
preparedStatement.close();
resultSet.close();
// smt.close();
conn.close();
}
}
2.2 通常ログイン
2.3 ユーザー名・パスワードのエラー
ユーザー名またはパスワードの入力に誤りがあった場合、「"ユーザー名またはパスワードが正しくありません、再入力してください"」と表示されます。
2.4 SQLインジェクションのシミュレーション
以前と同じようにSQLインジェクションを記述し、テスト後にSQLインジェクションが発生しなくなる。
2.5 SQL構文エラーのシミュレート
プリプロセッサクラスを使用する際、シングルクォートまたはダブルクォートを使用して入力しても、SQL 構文エラーにならなくなりました。
3. 概要
StatementとPreparedStatementの主な相違点は以下の通りです。
- ステートメントは、静的なSQL文を実行するために使用され、事前に準備されたSQL文は、実行時に指定する必要があります。
- PrepareStatementはコンパイル済みのSQL文オブジェクトで、実行時に"?"パラメータ値を動的に設定することが可能です。
- PrepareStatementはコンパイル時間を短縮し、データベースのパフォーマンスを向上させることができる
サマライズ
この記事は、SQLインジェクションとそれを解決する方法について紹介し、より関連するSQLインジェクションと解決策の内容は、スクリプトハウスの過去の記事を検索してくださいまたは次の関連記事を閲覧し続けることは、今後、よりスクリプトハウスをサポートして願っています!.
関連
-
Navicat 15アクティベーションチュートリアル
-
Navicat for SQLite インストールチュートリアル(インストールキット付き
-
Hbaseカラムナーストレージ入門チュートリアル
-
Navicat for Mac システムチュートリアルのインストールと使用方法
-
Dbeaverを使ったHiveへのリモート接続の詳細方法
-
Navicat Premium 15データベース接続フラッシュバックの問題を解決する
-
外部キーの関連付けを行う SQL 文の完全な例
-
Navicat Premiumを使用して、データベースのテーブル構造情報をExcelにエクスポートする方法
-
タイプインジェクションとコミットインジェクションのSQLインジェクションチュートリアル
-
SQLにおけるwhereとhavingの違いについて解説します
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ツリー構造データベースのテーブルのスキーマ設計のための2つのオプション
-
DataGripでクリックハウスの時間フィールドが正しく表示されない
-
DataGrip データエクスポート/インポート実装例
-
Djangoプロジェクト最適化データベース運用まとめ
-
gaussDBデータベース共通操作コマンド詳細
-
ナビカット15のインストールチュートリアルを超詳しく解説(一番信頼できるのはこれ)
-
QtによるOpenGaussデータベースへの接続の詳細チュートリアル
-
SQL実行エンジンを自作する方法
-
Navicat sqlファイルのインポートとエクスポートを素早く行う方法
-
データベースキャッシュの最終的な整合性に関する4つのオプション