SQLインジェクションとは？その脅威と防止策の例を解説

<br>

## ■ はじめに
<br>

SQLインジェクションとは、データベースの操作に不正なSQL文を挿入する攻撃手法のことです。
この攻撃が通ってしまう悪意のあるユーザーはデータベース内の情報を不正に取得、改ざん、削除することが可能となってしまいます。

SQLインジェクションはウェブアプリケーションの脆弱性を悪用した代表的な攻撃の一つで、
過去に多くの企業やサービスで深刻な問題を引き起こしています。

本記事ではそのSQLインジェクションがどのように行われるか、またその防止策について解説します。

## ■ 目次
<br>

1. [SQLインジェクションとは？](#1-sqlインジェクションとは)
2. [SQLインジェクションの危険性](#2-sqlインジェクションの危険性)
3. [SQLインジェクションの例](#3-sqlインジェクションの例)
4. [SQLインジェクションの防止策](#4-sqlインジェクションの防止策)
5. [まとめ](#5-まとめ)


## 1. SQLインジェクションとは？
<br>

SQLインジェクションは、ウェブアプリケーションがユーザーからの入力を適切に処理せず、
そのままデータベースに渡してしまう際に起こる脆弱性攻撃です。
攻撃者は意図的にSQL文をユーザー入力欄（テキストボックスやURLなど）に挿入することで、
データベースに対して不正な操作を行うことができてしまう場合があります。

```sql
SELECT * FROM users WHERE username = 'user1' AND password = 'password123';
```

上記は`username`や`password`にユーザーの入力がそのままハードコーディングされているため、
攻撃者がそこを書き換えることが可能な場合にSQLインジェクションを行う余地が残されています。

## 2. SQLインジェクションの危険性
<br>

SQLインジェクションの主な危険性についてです。

- データ漏洩
    - 攻撃者が通常アクセスできないデータベースの内容を取得可能になる

- データ改竄
    - データベース内のデータを不正に変更されるリスクがある

- システムを破壊
    - 特定のSQL文を使用することで、データベースやアプリケーション全体が破壊される可能性がある

- 認証の不正通過
    - 正しいユーザー名やパスワードを入力せずにシステムにアクセスできるようになる可能性がある

SQLインジェクションでは上記のような事象を意図的に発生させることができてしまうようになるため、
攻撃する余地を残さないよう対策が必要になります。

そもそもどのようにしてSQLインジェクションが発生してしまうか、といったことについては次で解説します。

## 3. SQLインジェクションの例
<br>

SQLインジェクション攻撃の例を挙げ具体的にどのようなクエリが生成されるかを見てみます。

### 攻撃例1: 認証の不正通過

攻撃者が、ログインフォームに以下のような入力を行ったとします。

ユーザー名: `admin' --`
パスワード: （空欄）

上記の入力を行った場合、実行時にはこのようなSQLクエリを生成します。

```sql
SELECT * FROM users WHERE username = 'admin' -- ' AND password = '';
```

admin' の「' 」で、まずユーザー名の入力を終わらせており、次の`--`はSQLのコメントアウトを意味するため、
本来あるはずの`AND`で結合されたパスワード条件が無視されてしまいます。
結果として、攻撃者は正しいパスワードを入力せずにadminユーザーとしてログインできてしまうことになります。

### 攻撃例2: データの抽出

攻撃者が、ログインフォームに以下のような入力を行ったとします。

ユーザー名: ' OR '1'='1
パスワード: （空欄）

上記の入力を行った場合、実行時にはこのようなSQLクエリを生成します。

```sql
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '';
```

' OR '1'='1の最初の「'」で、本来の条件を区切ってしまいます。
更に続けてOR '1'='1との条件が追加されることで、'1'='1'は常に真となる条件式になるため
このクエリは全てのユーザー情報を取得することが可能となってしまいます。

## 4. SQLインジェクションの防止策
<br>

SQLインジェクションを防ぐためには、アプリケーション側で適切な入力処理とクエリ実行の仕組みを整えることが重要です。
また主要な防止策としては以下のような例が挙げられます。

### 1. プリペアードステートメントの使用
これはSQLインジェクションを防ぐための強力な手段です。
ユーザー入力をパラメータ化することで、不正なSQL文の実行を防ぎます。

以下はJAVAでのプリペアードステートメントで、SQLクエリ内に直接値を埋め込むのではなく`?`という
プレースホルダを使って後から値をセットする仕組みです。

```java
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
```

またプリペアードステートメントは一度解析/コンパイルされた後に再利用されるため、
複数回のクエリ実行時にパフォーマンスが向上するといったメリットも存在します。

### 2. 権限管理
データベースユーザーの権限を最小限に制限し、不必要な操作権限を与えないようにすることも重要です。
アプリケーション用のデータベースユーザーには、必要最低限の参照権限のSELECT権限のみを与えることで、
それ以外のINSERT、DELETE、UPDATEを行うことを制限させる目的があります。

### 3. Webアプリケーションファイアウォールの導入
SQLインジェクション攻撃を防ぐためのもう一つの強力なツールが `WAF` [^1]です。
WAFは、アプリケーションに到達する前に疑わしいリクエストをブロックする役割のあるツールです。

SQL文に不正なパラメータが含まれていないかチェックし、攻撃の可能性があるリクエストをブロックしたり
SQLインジェクション遺体の攻撃（クロスサイトスクリプティング）やDDos攻撃からも守ります。

WAFを導入する場合にはウェブアプリケーション自体のコードを修正する必要がなく、
新しい脅威に対してもルールセットを更新するだけで攻撃を防ぐことが可能なツールです。


## 5. まとめ

- SQLインジェクションはデータベースの脆弱性を狙った攻撃で
    - 深刻なセキュリティリスクを引き起こす可能性がある
    - データ漏洩や認証バイパスなど、様々な危険性がある
    - プリペアードステートメントや入力値のエスケープなどで防止策を取る
    - また、WAFの導入や権限管理も重要な対策となる

[^1]:Webアプリケーションファイアウォール (WAF: Web Application Firewall) の略で、ウェブアプリケーションへの攻撃から守るためのセキュリティソリューション。