はじめに
業務で上司が書いたハッシュ化のコードの中に**"salt"**という記述がありました。
**「パスワードに塩をかけるとはどういうこと?」**と思い、調べてみたら意外と奥が深かったのでまとめました。
対象者
この記事は下記のような人を対象にしています。
- 駆け出しエンジニア
- プログラミング初学者
- ログインまわりを初めて実装する人
- PHPのmd5関数を使ってる人
結論
パスワードの漏洩対策に使用されるハッシュ化ですが、**ソルト(salt)やペッパー(pepper)**という手法を用いるとより安全に運用できます。
不安 | まぁまぁ安心 | より安心 |
---|---|---|
ハッシュ化のみ | ハッシュ化+ソルト(salt) | ハッシュ化+ソルト(salt)+ペッパー(pepper) |
本記事ではスコープ外なので解説しませんが、実用上はストレッチングも用いたほうが良いです。
ハッシュ化とは
ハッシュ化とは、元データ(文字列)をハッシュ値(文字列)に不可逆変換することを指します。
ハッシュ化を実行する関数をハッシュ関数と呼びます。
ハッシュ関数は様々な種類があり、md5やsha-256,sha-512,bcryptなどが有名ですが、今回はmd5を使用します!
md5関数を使用した例を下記に示します。
<?php
print ('ガンダム: '.md5('ガンダム')."\n");
print ('ガンキャノン: '.md5('ガンキャノン')."\n");
print ('ガンタンク: '.md5('ガンタンク')."\n");
?>
//結果
ガンダム: e87f1086f7bf9f59f1ec0b2dd2f320a4
ガンキャノン: e44e4ca716d4df9d1d4553641f77a00c
ガンタンク: 7faab3c51029273da3ee78d36e82f788
ハッシュ化の特徴
パスワードをユーザーテーブルに保存することが多いと思いますが、パスワードの文字列をそのまま保存すると**漏洩した場合に大変なことになります。**
ハッシュ化は不可逆なので、**「ハッシュ値から元のパスワードを復元することはできない」**ことが特徴です。
そのため、パスワードそのものではなく、ハッシュ値をテーブルに保存することで、漏洩時のリスクを減らすことができます。
ハッシュ化の課題
とはいえ、ハッシュ化にも課題があります。
不可逆変換とはいえ、入力値に対して出力されるハッシュ値は決まっているので、レインボーテーブル攻撃という手法でパスワードを特定することができます。
ユーザーが"123456"や"password"のようなイージーなパスワードを使用している場合、簡単に特定されてしまう恐れがあります。
ハッシュ化のソルト(salt)とは
ハッシュ化の課題(レインボーテーブル攻撃)を回避するために、ソルト(salt)という手法があります。
ソルト(salt)は元データ(文字列)に任意の文字列を加えてハッシュ化する手法です。
<?php
$salt = "mySalt";
print ('123456(ソルトなし): '.md5('123456')."\n");
print ('123456(ソルトあり): '.md5('123456'.$salt)."\n");
?>
//結果
123456(ソルトなし): e10adc3949ba59abbe56e057f20f883e
123456(ソルトあり): b8d06f590de08403b61e9ef59b81ad33
"123456"のようなよく使われるパスワードでもソルトを使用することで、異なるハッシュ値に変換され、レインボーテーブル攻撃対策になります。
ハッシュ化のソルト(salt)の課題
万能そうに見えるソルト(salt)にも課題があります。
それは**「ソルト(salt)はパスワードのハッシュ値と同じテーブルに保存されることが多い」**ということです。
データが漏洩する場合、ハッシュ値とセットでソルト(salt)も漏洩している場合が多いでしょう。
漏洩したソルト(salt)を使って簡単にハッシュ値からパスワードを特定できてしまうのです。
ハッシュ化のペッパー(pepper) / シークレットソルト(secret salt)とは
同時に漏洩しないように、ハッシュ値とは別に階層(.env等)にソルトを保存する手法をペッパー(pepper)と呼びます。
ソルト(salt)と別物のように聞こえますが、シークレットソルト(secret salt)という呼び方もあります。
ハッシュ値と別の階層に保存されているため、同時に流出することがありませんので、リスクを低減できます。
実際の使用例を下記に示します。
#.env
MYPEPPER = "myPepper"
<?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)の役割と効果
今さら聞けないハッシュ化
暗号化に用いるSaltの課題を解決するSecret Salt
4枚の図解でわかるレインボーテーブル攻撃