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

インジェクションとは

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

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

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

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

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

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

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

  一般アカウントで不正ログインされてしまった場合、
  その一般アカウントの個人情報が盗まれてしまう。(漏えいしてしまう)
  一般アカウントの権限で可能な操作が不正に行われてしまう(ECサイトで商品購入等)

  管理者アカウントで不正ログインされてしまった場合、
  多くの一般アカウントの個人情報が盗まれてしまう。(漏えいしてしまう)
  管理者アカウントの権限で可能な操作が不正に行われてしまう(Webサイトの内容改ざん等)

3.DBのデータが不正に消去(Delete)される。

4.不正ログインされる

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

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


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';

●画面
 

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

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またはパスワードが間違っています");
        }
    }

上記どちらかの対応をすれば、パスワード欄に「hogehoge ‘ OR ‘1’=’1」等と入力されてもログインが成功しなくなる。

タイトルとURLをコピーしました