SQLインジェクションを防止しよう

## はじめに

ウェブアプリケーションのセキュリティは、現代の開発者にとって欠かせない要素です。その中でも特に注意が必要なのが「SQLインジェクション攻撃」です。攻撃者が悪意のあるSQLコードを注入し、データベースに不正アクセスする手法であり、多くの被害報告があります。この記事では、SQLインジェクション攻撃を防ぐための対策をまとめます！

### （ここで宣伝）
弊社の開発プロジェクトに参画いただける方（フリーランスのエンジニアの方）を大募集しております！

現在、様々な開発プロジェクトがあり、開発の部分に携わっていただける方をどうにか探しているところです。
サーバーサイド、フロントエンド、インフラ等、どんなポジションでも歓迎しております。
要件定義や設計のフェーズから携ることのできる案件も結構あり、自分の得意な分野を活かせるプロジェクトが絶対あるかと思います！

興味のある方は是非下記フォームに回答して、弊社の開発プロジェクトに参加してください！
（詳細は回答いただいた後、ご連絡いたします）

👉 フォームは[こちら](https://docs.google.com/forms/d/e/1FAIpQLSfY9lckFjAJ_Ddc4rdHDSIFoV4NFHw1q2HriK2aa_jvVhp8QQ/formResponse)

ご回答のほど、お待ちしております！

## SQLインジェクションとは？

SQLインジェクション（SQL Injection）は、攻撃者がウェブアプリケーションの入力フィールドに悪意のあるSQLコードを挿入し、データベースに対して不正な操作を行う攻撃手法です。これにより、データの漏洩、改ざん、削除などが引き起こされる可能性があります。

### 主なリスク


- **データ漏洩:** ユーザー情報や機密データが外部に流出する。
- **データ改ざん:** データベース内の情報が不正に変更される。
- **サービス停止:** データベースが破壊され、アプリケーションが機能しなくなる。
- **不正アクセス:** 管理者権限を取得し、システム全体を掌握される可能性。

## SQLインジェクションの仕組み

SQLインジェクション攻撃は、主に以下のような手順で行われます。

1. **脆弱な入力フィールドの特定:** ログインフォームや検索バーなど、ユーザーが入力できるフィールドを探します。
2. **悪意のあるSQLコードの挿入:** 例えば、`' OR '1'='1` のようなコードを入力します。
3. **データベースの操作:** 挿入されたSQLコードが実行され、データベースに対して不正な操作が行われます。

## SQLインジェクションの防止策



### 防止策紹介の前に
これから防止策の例を記載していくのですが、前提、それを見る前に
[安全なウェブサイトの作り方
](https://www.ipa.go.jp/security/vuln/websecurity/about.html) を確認することを強くお勧めします！
こちらはIPA提供のwebサイト開発時のセキュリティ対策についてのガイドラインのようなもので、SQLインジェクションをはじめとしたセキュリティ対策が広くまとまっています。
サイトからセキュリティ対策のチェックリストもダウンロード可能なので、リストをたまに見ながら開発を進めるといいかもしれません！

### 1. プリペアドステートメントとパラメータ化クエリの使用

プリペアドステートメント（Prepared Statements）やパラメータ化クエリを使用することで、SQLインジェクションのリスクを大幅に減少させることができます。これらの手法では、ユーザー入力が自動的にエスケープされ、SQLコードとして解釈されません。

**例: JavaScript（Node.js）と`pg`モジュールを使用したパラメータ化クエリ**

```jsx
const { Client } = require('pg');

const client = new Client({
  user: 'username',
  host: 'localhost',
  database: 'testdb',
  password: 'password',
  port: 5432,
});

client.connect();

const username = req.body.username;
const password = req.body.password;

const query = 'SELECT * FROM users WHERE username = $1 AND password = $2';
const values = [username, password];

client.query(query, values, (err, res) => {
  if (err) {
    console.error(err);
    res.status(500).send('エラーが発生しました');
  } else {
    if (res.rows.length > 0) {
      res.send('ログイン成功');
    } else {
      res.send('ログイン失敗');
    }
  }
  client.end();
});
```

この例では、`pg`モジュールを使用してPostgreSQLデータベースに接続し、パラメータ化クエリを実行しています。ユーザー入力が安全に処理され、SQLインジェクションのリスクが低減されます。

### 2. 入力バリデーションとサニタイズ

ユーザーからの入力を受け取る際には、必ずバリデーション（検証）とサニタイズ（無害化）を行いましょう。特に、数値や特定の形式が求められる入力に対しては、期待されるデータ型やフォーマットを確認します。

**例: JavaScript（Node.js）での入力バリデーション**

```jsx
function validateInput(input) {
  // 数値のみを許可
  const regex = /^\d+$/;
  return regex.test(input);
}

const userInput = req.body.userInput;

if (validateInput(userInput)) {
  // 安全な入力
} else {
  res.status(400).send('無効な入力です。数値のみを入力してください。');
}

```

この例では、ユーザー入力が数値であることを検証し、不正な入力を排除しています。

### 3. ORM（オブジェクトリレーショナルマッピング）の利用

ORMを使用することで、データベースとのやり取りを抽象化し、手動でSQLクエリを書く必要がなくなります。多くのORMは内部でパラメータ化クエリを使用しているため、SQLインジェクションのリスクが低減されます。

**例: JavaScript（Node.js）とPrisma ORMを使用した安全なデータベース操作**

```jsx
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();

async function loginUser(req, res) {
  const { username, password } = req.body;

  try {
    const user = await prisma.user.findFirst({
      where: {
        username: username,
        password: password,
      },
    });

    if (user) {
      res.send('ログイン成功');
    } else {
      res.send('ログイン失敗');
    }
  } catch (error) {
    console.error(error);
    res.status(500).send('エラーが発生しました');
  } finally {
    await prisma.$disconnect();
  }
}

```

この例では、Prisma ORMを使用してユーザー情報を安全に取得しています。Prismaが内部でクエリをパラメータ化するため、SQLインジェクションのリスクが自動的に低減されます。

### 4. データベースの権限管理

データベースユーザーには必要最低限の権限のみを付与しましょう。特に、アプリケーションが必要としない権限（例: DROP、DELETE）を持たせないことで、万が一攻撃を受けても被害を最小限に抑えることができます。

**例: PostgreSQLでの権限設定**

```sql
-- 新しいユーザーを作成
CREATE USER app_user WITH PASSWORD 'secure_password';

-- 必要な権限のみを付与
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO app_user;
```

この例では、`app_user`というユーザーに対して、必要な権限のみを付与しています。

### 5. エラーメッセージの制御

データベースやアプリケーションのエラーメッセージには、内部の詳細情報を含めないようにしましょう。具体的なエラー情報を攻撃者に提供すると、攻撃の手助けになる可能性があります。

**例: エラーハンドリングの改善**

```jsx
try {
  // データベース操作
} catch (error) {
  console.error(error);
  res.status(500).send('エラーが発生しました。後ほど再度お試しください。');
}
```

この例では、内部エラーをログに記録し、ユーザーには一般的なエラーメッセージを表示しています。

## まとめ

SQLインジェクション攻撃は、適切な対策をすることで防ぐことができます。今回紹介した、プリペアドステートメントやパラメータ化クエリの使用、入力バリデーションとサニタイズ、ORMの活用、データベースの権限管理、そしてエラーメッセージの制御といった対策をすることで、リスクを大幅に減らせます。
この記事を参考に、セキュアな開発への手助けになれれば幸いです！

## おわりに
繰り返しになりますが、弊社では、フリーランスエンジニアの方を募集しております！

熱意を持って新しいプロジェクトに挑戦したい方、様々な大規模開発プロジェクトに興味のある方は、下記フォームにてあなたの経歴をご回答ください！

👉 フォームは[こちら](https://docs.google.com/forms/d/e/1FAIpQLSfY9lckFjAJ_Ddc4rdHDSIFoV4NFHw1q2HriK2aa_jvVhp8QQ/formResponse)

たくさんのご応募、お待ちしております！