SQLインジェクションの原因と対策

PR

インジェクションとは

・「インジェクション」とは「Injection」。
・「Injection」の意味は「注入」。
・「注入」とは「注ぎ入れること」。

PR

SQLインジェクションとは(概要)

不正なSQL文をWebアプリ等へ入力(注ぎ入れること)により、
 ・不正にログイン
 ・不正にDBの情報取得
 ・不正にDBの情報改ざん/消去
をする攻撃のこと。

PR

SQLインジェクションとは(詳細)

入力フォームやテキストボックスに不正なSQL文を記載しWebアプリへリクエストを送る。
Webアプリ側で不正なSQLが実行されることにより、以下が発生しうる。

1.DBのデータが不正に参照(Select)される。
DBが不正に参照されることにより、レスポンスとして画面に個人情報等の機密情報が表示される。

機密情報が表示された画面が参照されることにより、不正に情報が取得される。
※漏えいしてしまう。

2.DBのデータが不正に改ざん(Update)される。改ざんにより不正ログインされる。
DBに登録されているログインパスワードが不正に変更(改ざん)される。
変更(改ざん)後のログインパスワードを使用されて、不正ログインされてしまう。

●一般アカウントで不正ログインされてしまった場合
当該アカウントの個人情報が盗まれてしまう。
※漏えいしてしまう。

また一般アカウントの権限で可能な操作が不正に行われてしまう。
※ECサイトで商品購入等。

●管理者アカウントで不正ログインされてしまった場合
多くの一般アカウントの個人情報が盗まれてしまう。
※漏えいしてしまう。

また管理者アカウントの権限で可能な操作が不正に行われてしまう。
※Webサイトの内容改ざん等。

3.DBのデータが不正に消去(Delete)される。
嫌がらせや愉快犯?

PR

SQLインジェクションの仕組み(不正ログインの場合)

前提
以下のようなログイン画面があるとします。

ログイン画面
ログイン画面


DB(ログイン情報)は以下になっているとします。

DB(ログイン情報)
DB(ログイン情報)


ログイン画面で入力されたユーザーIDとパスワードを使用して、以下のSQLを組み立てコーディングされているとします。
※プログラミング言語はC#で、DBはSQLiteの場合。

(省略)

userId = userIdText.Text;
password = password_text.Text;

sql = "select userName from user where userID = '" + userId + "' and password = '" + password + "';";

using (var conn = new SQLiteConnection("Data Source= sqlite.db"))
{
    conn.Open();
    SQLiteCommand cmd = conn.CreateCommand();
    cmd.CommandText = sql;
    using (SQLiteDataReader reader = cmd.ExecuteReader())
    {
        if(reader.HasRows == true)
        {
            reader.Read();
            MessageBox.Show("こんにちは!" + reader["userName"].ToString() + "さん!");
        }
        else
        {
            MessageBox.Show("ユーザーIDまたはパスワードが間違っています");
        }
    }
}


正しいユーザーIDとパスワードでログインした場合
以下のSQLが実行され、ログインが成功し以下の画面が表示される。

●実行されるSQL

select userName from user where userId = 'suzuki' and password ='123456';

●表示される画面(ログイン成功画面)

ログイン成功画面
ログイン成功画面

不正なパスワードでログインした場合
以下のSQLが実行され、ログインが失敗し以下の画面が表示される。

●実行されるSQL

select userName from user where userID = 'suzuki' and password = 'hogehoge';

●表示される画面(ログイン失敗画面)

ログイン失敗画面
ログイン失敗画面

SQLインジェクションで不正ログインした場合
ログイン画面のパスワード欄に以下を入力し、ログインを試みる。

①hogehoge ‘ OR ‘a’=’a または 
②hogehoge ‘ OR ‘1’=’1 または 
③’ OR ‘1’=’1

不正パスワードを入力①
不正パスワードを入力①
不正パスワードを入力②
不正パスワードを入力②
不正パスワードを入力③
不正パスワードを入力③


その結果、 以下のSQLが実行され
 ・ユーザーID及びパスワードが共に正しくなくともログインが成功
してしまう。

●実行されるSQL

select userName from user where userID = 'suzuki' and password = 'hogehoge ' OR 'a'='a';

または

select userName from user where userID = 'suzuki' and password = 'hogehoge ' OR '1'='1';

または

select userName from user where userID = '' and password = '' OR '1'='1';


●ログイン成功画面

不正パスワードでもログイン成功①
不正パスワードでもログイン成功①
不正パスワードでもログイン成功②
不正パスワードでもログイン成功②
不正パスワードでもログイン成功③
不正パスワードでもログイン成功③
PR

SQLインジェクションを防ぐ方法

SQLインジェクションを防ぐ方法は2種類ある。

1.エスケープ処理をする
具体的には
 ・ソースコード内で「’(シングルクォート)」を「”(ダブルクォート)」へ置換
する。

置換することにより、例えばパスワードに「hogehoge ‘ OR ‘1’=’1」が入力された場合、

select userName from user where userID = 'suzuki' and password = 'hogehoge ' OR '1'='1';

でなく

select userName from user where userID = 'suzuki' and password = 'hogehoge ” OR ”1”=”1'; 

が実行されるようにする。

サンプルプログラムは以下。

(省略)
string sql;

//「’(シングルクォート)」を「”(ダブルクォート)」へ置換する
userId = userIdText.Text.Replace("\'", "\"");
password = password_text.Text.Replace("\'", "\"");

sql = "select userName from user where userID = '" + userId + "' and password = '" + password + "';";
(省略)


2.静的プレースホルダ(プリペアドステートメント)を使用する
画面に入力された値(OR ‘1’=’1等)を「SQL」でなく「文字列」と解釈されるようにするために静的プレースホルダ(プリペアドステートメント)を使用する。

SQLインジェクションが起きてしまうのは、画面に入力された値(OR ‘1’=’1等)をSQLとして解釈してしまうため。

実際に実行されるSQLはデータベース側で組み立てられるため、ソースコード上で(デバックで)確認できない。

(省略)
string userId;
string password;
string sql;

userId = userIdText.Text;
password = password_text.Text;

//「:userId」と「:password」がプレースホルダ
sql = "select userName from user where userId = :userId and password = :password ;";

using (var conn = new SQLiteConnection("Data Source= sqlite.db"))
{
    conn.Open();
    SQLiteCommand cmd = conn.CreateCommand();
    cmd.CommandText = sql;
  
  //プリペアドステートメントを使用してプレースホルダ「:userID」と「:password」に
  //画面から入力された値を(文字列として)設定する(バインドする)
    cmd.Parameters.Add("userId", System.Data.DbType.String).Value = userId;
    cmd.Parameters.Add("password", System.Data.DbType.String).Value = password;

    using (SQLiteDataReader reader = cmd.ExecuteReader())
    {
        if(reader.HasRows == true)
        {
            reader.Read();
            MessageBox.Show("こんにちは!" + reader["userName"].ToString() + "さん!");
        }
        else
        {
            MessageBox.Show("ユーザーIDまたはパスワードが間違っています");
        }
    }


上記の2種類の内のどちらかの対応をすれば、パスワード欄に「hogehoge ‘ OR ‘1’=’1」等を入力されても、ログインは成功しなくなる。
※SQLインジェクションを防げる。

不正パスワードの場合はログイン失敗
不正パスワードの場合はログイン失敗
タイトルとURLをコピーしました