押さえておきたいセキュリティと対策！

こんにちは！もうすぐ3年目を迎える受託系企業で働くガッキーです。
2年目のうちに知っておかなきゃいけない知識とか実装とか焦りながら考えていたら、
まず思い浮かんだことがセキュリティだったので書いてみました！


# なぜセキュリティを守らなければならないのか！？

そもそもなぜセキュリティを確保しなければならないのか？

- 第三者への情報漏洩
- 情報の改ざん
- 第三者による不正な利用

これらを確保せずアプリケーションを確保すれば、
利用者への被害が拡大しアプリの信頼が失われ、会社経営への影響が出てきてしまうのです。

さっそく押さえておきたいセキュリティを見ていきましょう！


# 1.SQLインジェクション

:::note info
SQLインジェクションとは？

入力フォームにSQL文を入力し送信することでデーターベースの改ざんや取得がされてしまうものです。
:::


不正なselect・delete・update文を入力することで、
そこから個人情報が流失し、ユーザー情報が改ざんされ様々な問題に発展します。

例えば、ログイン画面のID・PWフォームに以下のような値を入力して送信するとします。

ログイン名：hoge
パスワード：foo' or 'foo' = 'foo

上記の値が送信されて発行されるSQLが以下のようになります。

```sql
SELECT * FROM users WHERE username = 'hoge' AND password = 'foo' or 'foo' = 'foo';
```

このwhere句に注目ですが`'foo' = 'foo'`の部分はこのようになり、

```sql
WHERE TRUE;
```

Usersテーブルの内容が全て参照されてしまうのです！

## 対策👮

### 入力値チェック（バリデーションチェック）

例えばパスワードの入力であれば、
- 半角英数字の入力であるか？
- 指定文字数であるか？

とすれば先ほどの値の混入は防ぐことができます。

### プリペアードステートメント

プリペアードステートメントとは文字列連結のSQLとして処理を実装するのではなく、
条件によって変化するwhere句についてプレースホルダとして登録したSQLを用意してから後からパラメーターを割り当てる方法です。

```php
$username = 'hoge';
$password = 'TRUE';

$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
$stmt->execute(['username' => $username, 'password' => $password]);
$results = $stmt->fetchAll();
```

上記はPHPのPDOを使用したケースです。
ユーザー名とパスワードをプレースホルダとすることで、
仮に$passwordに`foo' or 'foo' = 'foo`が送信されても
PDOでエスケープされて生のSQLとして実行されず

```sql
SELECT * FROM users WHERE username = 'hoge' AND password = 'foo'' or ''foo'' = ''foo'
```

このようにpasswordの値として``foo' or 'foo' = 'foo``のユーザーであることが条件になるため、


悪意のあるSQL文が直接実行されるのを防いで、不正な参照を防ぐことが出来るのです！
フレームワークのORMではプリペアードステートメントが利用されているので、
フレームワークを使うことがセキュリティ対策にも繋がります。


# 2.クロスサイトスクリプティング(XSS)
:::note info
クロスサイトスクリプティング(XSS)とは？
入力フォームに悪意のあるJavaScriptが埋め込まれることによって不正ログイン、個人情報の流出、悪意のあるサイトへ誘導がされてしまうものです。
:::

具体的な流れは、

1. リンクが記載されたJavaScriptがフォームに埋め込まれる
2. ブラウザで埋め込まれたスクリプトをそのまま実行
3. ユーザーがリンクをクリックすることで悪意のあるサイトに誘導される

このように悪意のあるサイトに誘導されることで、
ブラウザに保存されているCookieが抜き取られ、
重要な情報が抜き取られてしまうことに繋がってしまうのです。

## 対策👮

### 入力値チェック（バリデーションチェック）

ここでもSQLインジェクション同様に入力値チェックを行うことが対策の一つとして考えられます。
全ての入力フォームに対して、許可されない文字列やコードは登録できないような
バリデーションチェックを実装する必要があります。

### エスケープ処理

エスケープ処理とは入力値を画面に表示させる際に、HTMLの構造を変更・削除される文字列を無効化する処理をいいます。

例えば、以下のような文字列がエスケープ処理によって変換されます。

```
<（小なり記号） → &lt;
>（大なり記号） → &gt;
&（アンパサンド） → &amp;
"（ダブルクォート） → &quot;
```

実際にPHPのエスケープ処理を見てみましょう！

```php
// ユーザー入力
$user_input = '<script>alert("XSS")</script>';

// エスケープ処理
$escaped_input = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');

// エスケープされた入力を表示
echo $escaped_input;
// 出力: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;
```

エスケープすることで埋め込まれたスクリプトを無効化することが出来ます！

# 3.セッションハイジャック
:::note info
セッションハイジャックとは？
ユーザーにセッションIDが第三者に盗まれることで、
第三者がユーザーになりすましてサービスを不正利用する行為です。
:::

セッションハイジャックされる流れ

1. ユーザーがアプリにログインしてサービスを利用
1. 第３者がCookieやGETリクエストからユーザーのセッションIDを取得
1. 第３者ユーザーになりすましサービスを不正利用

## 対策👮

### 通信経路の暗号化

暗号化されていないhttp通信では、データが平文で送信されるため
セッションIDが盗まれたり改ざんされるリスクが非常に高いです。

このため通信が暗号化されているhttpsを使用することで、
第三者によるデータの盗聴や改ざんを防ぐことができます。

### セッションタイムアウト

セッション情報の有効時間を短くすることで、
セッションIDが盗まれた場合でも、悪用されるリスクを減らすことが出来ます。

### セッションIDを推測困難なものにする

セッションIDを

- ランダム値：数字、アルファベットの大文字・小文字、および特殊文字を含む値
- 十分な長さ：32文字以上

このようにすることで推測が困難になります。

# 4.クロスサイトリクエストフォージェリ（CSRF）

:::note info
クロスサイトリクエストフォージェリとは？
第3者が捏造したフォームからデータ送信することで、
ユーザーの利用するサービスに不正な処理が行われてしまうことです。
:::

具体例）

1. ユーザーが銀行のウェブサイトにログインします。
2. 同じブラウザで悪意のあるウェブサイトにアクセスします。
3. 悪意のあるサイトから、ユーザーの銀行口座から別の口座にお金を送金するリクエストを自動的に送信します。
4. 銀行のウェブサイトはそれを正当なリクエストとみなし、送金を実行します。

これめっちゃ怖いですね…

## 対策👮

### CSRFトークン

CSRFが行われてしまう原因は銀行のサイトへ、
悪意のあるサイトからリクエストが受信されてしまっているところにあります。
銀行サイトが用意した入力フォームからのリクエストであるかチェックする必要があります。
各リクエストにユニークなトークンを含め、トークンを検証し、正当なリクエストであることを確認します。

## まとめ

ご覧いただきありがとうございました！
普段なにげなく実務でアプリを作っていましたが、
気づいていないところでフレームワークが補完してくれているところが
沢山あることを知りました！

何か気になる点や、おかしな点ありましたらお気軽にコメントください！