ハッシュ化のソルト(salt)とペッパー(pepper)についてまとめた

## はじめに
業務で上司が書いたハッシュ化のコードの中に**"salt"**という記述がありました。
**「パスワードに塩をかけるとはどういうこと？」**と思い、調べてみたら意外と奥が深かったのでまとめました。
![塩](https://media.giphy.com/media/l4Jz3a8jO92crUlWM/giphy.gif "塩")

## 対象者
この記事は下記のような人を対象にしています。

- 駆け出しエンジニア
- プログラミング初学者
- ログインまわりを初めて実装する人
- PHPのmd5関数を使ってる人

## 結論
パスワードの漏洩対策に使用されるハッシュ化ですが、**ソルト(salt)やペッパー(pepper)**という手法を用いるとより安全に運用できます。

| 不安 |    まぁまぁ安心     |    より安心    |
|:---:|:-------------:|:------------:|
| ハッシュ化のみ  | ハッシュ化+ソルト(salt)| ハッシュ化+ソルト(salt)+ペッパー(pepper) |

本記事ではスコープ外なので解説しませんが、実用上はストレッチングも用いたほうが良いです。

## ハッシュ化とは
ハッシュ化とは、**元データ(文字列)をハッシュ値(文字列)に不可逆変換すること**を指します。
ハッシュ化を実行する関数をハッシュ関数と呼びます。
ハッシュ関数は様々な種類があり、md5やsha-256,sha-512,bcryptなどが有名ですが、今回はmd5を使用します！

md5関数を使用した例を下記に示します。

```php:example.php
<?php
print ('ガンダム: '.md5('ガンダム')."\n");
print ('ガンキャノン: '.md5('ガンキャノン')."\n");
print ('ガンタンク: '.md5('ガンタンク')."\n");
?>

//結果
ガンダム: e87f1086f7bf9f59f1ec0b2dd2f320a4
ガンキャノン: e44e4ca716d4df9d1d4553641f77a00c
ガンタンク: 7faab3c51029273da3ee78d36e82f788
```
### ハッシュ化の特徴
パスワードをユーザーテーブルに保存することが多いと思いますが、パスワードの文字列をそのまま保存すると**<font color="Red">漏洩した場合に大変なことになります。</font>**
ハッシュ化は不可逆なので、**「ハッシュ値から元のパスワードを復元することはできない」**ことが特徴です。
そのため、パスワードそのものではなく、**ハッシュ値をテーブルに保存**することで、漏洩時のリスクを減らすことができます。

### ハッシュ化の課題
とはいえ、ハッシュ化にも課題があります。
不可逆変換とはいえ、入力値に対して出力されるハッシュ値は決まっているので、**<font color="Red">レインボーテーブル攻撃という手法でパスワードを特定することができます。</font>**
ユーザーが"123456"や"password"のようなイージーなパスワードを使用している場合、**<font color="Red">簡単に特定されてしまう恐れがあります。</font>**

## ハッシュ化のソルト(salt)とは
ハッシュ化の課題(レインボーテーブル攻撃)を回避するために、ソルト(salt)という手法があります。
ソルト(salt)は**元データ(文字列)に任意の文字列を加えてハッシュ化する**手法です。

```php:example.php
<?php
$salt = "mySalt";
print ('123456(ソルトなし): '.md5('123456')."\n");
print ('123456(ソルトあり): '.md5('123456'.$salt)."\n");
?>

//結果
123456(ソルトなし): e10adc3949ba59abbe56e057f20f883e
123456(ソルトあり): b8d06f590de08403b61e9ef59b81ad33
```
"123456"のようなよく使われるパスワードでもソルトを使用することで、異なるハッシュ値に変換され、**<font color="Blue">レインボーテーブル攻撃対策になります。</font>**

### ハッシュ化のソルト(salt)の課題
万能そうに見えるソルト(salt)にも課題があります。
それは**<font color="Red">「ソルト(salt)はパスワードのハッシュ値と同じテーブルに保存されることが多い」</font>**ということです。
データが漏洩する場合、ハッシュ値とセットでソルト(salt)も漏洩している場合が多いでしょう。
漏洩したソルト(salt)を使って簡単にハッシュ値からパスワードを特定できてしまうのです。

## ハッシュ化のペッパー(pepper) / シークレットソルト(secret salt)とは
同時に漏洩しないように、**ハッシュ値とは別に階層(.env等)にソルトを保存する手法**をペッパー(pepper)と呼びます。
ソルト(salt)と別物のように聞こえますが、シークレットソルト(secret salt)という呼び方もあります。
ハッシュ値と別の階層に保存されているため、同時に流出することがありませんので、**<font color="Blue">リスクを低減できます。</font>**

実際の使用例を下記に示します。

```php:.env
#.env
MYPEPPER = "myPepper"
```
```php:example.php
<?php
require 'vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

$pepper = $_ENV["MYPEPPER"]; // .envからペッパー読込
print ('123456(ペッパーなし): '.md5('123456')."\n");
print ('123456(ペッパーあり): '.md5('123456'.$pepper)."\n");
?>

// 結果
123456(ペッパーなし): e10adc3949ba59abbe56e057f20f883e
123456(ペッパーあり): e1b76e76809f8c5d59b279b37fa2acd2
```
.envからペッパーを読み込んで、ハッシュ化できていますね！

## おわりに
ハッシュ化をさらに堅牢にするソルト(salt)とペッパー(pepper)についてまとめました。
パスワード周りを実装する際には、ハッシュ化だけで満足せずにソルト(salt)やペッパー(pepper)を活用しましょう！

## 参考記事
[パスワードハッシュ化で用いるソルト(Salt)とペッパー(Pepper)/シークレットソルト(Secret Salt)の役割と効果](https://qiita.com/shioshiota/items/d439e63c4ee651d956ab)
[今さら聞けないハッシュ化](https://zenn.dev/nekoniki/articles/6f07ff4423f194)
[暗号化に用いるSaltの課題を解決するSecret Salt](https://tamata78.hatenablog.com/entry/2020/11/25/163416)
[4枚の図解でわかるレインボーテーブル攻撃](https://persol-tech-s.co.jp/corporate/security/article.html?id=57)