OWASP ASVS 4.0 V2.4 からパスワードの保存を考える

# OWASP ASVSとは
Application Security Verification Standard 4.0 - アプリケーションセキュリティ検証基準です。検証つまりテストに関する基準なのですが、WebアプリケーションおよびWebサービスを設計、開発およびテストする時のセキュリティ要件についてまとめられています。

> 本ページでは、下記を参考にさせていただいております。
OWASP ASVS 4.0：https://owasp.org/www-project-application-security-verification-standard/
日本語訳参考：https://qiita.com/prt445/items/42856a66666aae65a16e

## V2.4 Credential Storage Requirements
V2は、認証に関する検証要件です。その中のV2.4は、クレデンシャル保管要件です。

実際の要件は下表です。

ここでL1,L2,L3は、ASVSレベルと呼ばれるもので、レベルが上がるにつれてより詳細な要件になります。
L1：低保証アプリケーション用のレベルです。ペネトレーションテストが可能な要件になってます。
L2：機密データ、個人情報を含むアプリケーション用のレベルです。ほとんどのアプリケーションに推奨される要件になってます。
L3：最も重要なアプリケーション、高額の取引、医療情報などを扱うアプリケーション用のレベルです。

NIST &sect;は、NIST（米国国立標準技術研究所） Special Publication 800-63Bというドキュメントの対応する項目です。OWASP ASVS 4.0の認証やセッションに関する要件はこのドキュメントに準拠しています。

| # | Description | L1 | L2 | L3 | CWE | [NIST &sect;](https://pages.nist.gov/800-63-3/sp800-63b.html) |
| :---: | :--- | :---: | :---:| :---: | :---: | :---: |
| **2.4.1** | Verify that passwords are stored in a form that is resistant to offline attacks. Passwords SHALL be salted and hashed using an approved one-way key derivation or password hashing function. Key derivation and password hashing functions take a password, a salt, and a cost factor as inputs when generating a password hash.  | | ✓ | ✓ | 916 | 5.1.1.2 |
| **2.4.2** | Verify that the salt is at least 32 bits in length and be chosen arbitrarily to minimize salt value collisions among stored hashes. For each credential, a unique salt value and the resulting hash SHALL be stored.  | | ✓ | ✓ | 916 | 5.1.1.2 |
| **2.4.3** | Verify that if PBKDF2 is used, the iteration count SHOULD be as large as verification server performance will allow, typically at least 100,000 iterations.  | | ✓ | ✓ | 916 | 5.1.1.2 |
| **2.4.4** | Verify that if bcrypt is used, the work factor SHOULD be as large as verification server performance will allow, typically at least 13. | | ✓ | ✓ | 916 | 5.1.1.2 |
| **2.4.5** | Verify that an additional iteration of a key derivation function is performed, using a salt value that is secret and known only to the verifier. Generate the salt value using an approved random bit generator [SP 800-90Ar1] and provide at least the minimum security strength specified in the latest revision of SP 800-131A. The secret salt value SHALL be stored separately from the hashed passwords (e.g., in a specialized device like a hardware security module). |  | ✓ | ✓ | 916 | 5.1.1.2 |

とりあえず、一つずつ見ていきます。

### V2.4.1
パスワードを、オフライン攻撃に強い形式で保管すること。
オフライン攻撃に強い形式とは、承認済みの一方向鍵導出またはパスワードハッシュ関数を使用して、ハッシュ関数した形式です。その際には、パスワード、salt、コスト係数をパラメータとして指定します。

承認済みの一方向鍵導出またはパスワードハッシュ関数ですが、[OWASP Cheat Sheet - Password storage](https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet)を参考にすると、特に指定がない限り、Bcryptを使うように記載されております。NIST SP 800-63bでは、PBKDF2が推奨されてます。他には、Argon2などもありますが、Bcryptが使いやすいと思います。

### V2.4.2
saltの長さが少なくとも３２ビットで、パスワードごとに固有のsalt値をもつことを確認します。

もしくは、[OWASP Cheat Sheet - Password storage](https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet)を参考にすると、少なくとも16文字以上で、16進数やBase64などの安全な文字セットにエンコードする。また、saltを生成するときは、[CSPRNG](https://owasp.org/www-project-cheat-sheets/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-cryptographically-secure-pseudo-random-number-generators-csprng)を使いましょう。

ただし、モダンなアルゴリズム（BcryptやArgon2など）では、ソルトは自動で生成してくれます。その場合は、この章は意識しなくて良いです。

### V2.4.3
PBKDF2を使っている場合、少なくとも１００，０００回以上反復する必要がある。

PBKDF2とは、Password-Based Key Derivation Function 2の略で、ソルトを用いたハッシュ化を指定した反復回数繰り返し行い求めます。

例えば、PHPなら`hash_pbkdf2`という関数を使うことができます。

```php
hash_pbkdf2 ( string $algo , string $password , string $salt , int $iterations [, int $length = 0 [, bool $raw_output = FALSE ]] ) : string
```

`$iterations`が反復回数です。

例）

```php
$salt = bin2hex(random_bytes(16));
hash_pbkdf2('sha512', $password, $salt, 1000000);
```

### V2.4.4
bcryptを使っている場合、コストは少なくとも13にする必要がある。

例えば、PHPには`password_hash`という、まさしくな関数があり、デフォルトではbcryptを使います。

```php
password_hash ( string $password , int $algo [, array $options ] ) : string
```

`$algo`に`PASSWORD_BCRYPT`を指定すると、bcryptを使います。`PASSWORD_DEFAULT`を使ってもbcryptを使いますが、`PASSWORD_DEFAULT`の場合は、フルリリースの際にアルゴリズムが変更されることがあります。アルゴリズムが変更されると当然ハッシュ値が変わります。なので、個人的には、`PASSWORD_BCRYPT`を指定しておいた方が良いと思ってます。

さらに、`$options`に連想配列の形式で、`PASSWORD_BCRYPT`の場合はsaltとcostを指定することができます。ちなみに、アルゴリズムが変われば、オプションも変わります。詳しくは、[phpのドキュメント](https://www.php.net/manual/ja/function.password-hash.php)を見てください。

例）

```php
$options = [
    'cost' => 13
];
$hash = password_hash($password, PASSWORD_BCRYPT, $options);
```

PHPのマニュアルによると`salt`を指定することは、推奨されてません。指定しないと自動saltを付与してくれますので、簡単なsaltを付与する心配がありません。
また、パスワードハッシュを作成する関数としては、`hash_pbkdf2`よりも、`password_hash`が推奨されています。

検証するときは、下記のようにします。

```php
password_verify($password, $hash);
```

### V2.4.5
verifierだけが知っているsercretをsalt値として使って追加で鍵導出関数の反復が実行されることを確認する。（可能ならば）ソルト値は承認済み乱数生成器 [SP 800-90Ar1]を利用して生成されるべきであり，SP 800-131Aの最新版で指定されている最小のセキュリティ強度(NIST SP 800-63b公開時点で112ビット)を少なくとも備えるべきである。このsalt値は、パスワードハッシュとは別に保管する。

本要件は、俗にいうpepperのことではないかと思います。NIST SP 800-63bでは、secret saltと記載されてます。

```php
$pepper = bin2hex(random_bytes(16));
$options = [
    'cost' => 13
];
$password_hash =  password_hash($password . $pepper, PASSWORD_BCRYPT, $options);
```

また、[OWASP Cheat Sheet - Password storage](https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet)によると、パスワードハッシュを共通鍵暗号で暗号化して保管しても良いと記載されてます。上記の方法では、pepperが漏洩してしまった場合、pepperを変更してしまうと既存に保管しているパスワードハッシュが、変わってしまいます。長期間の運用には向いていません。

共通鍵暗号であれば、鍵の変更もしやすいですね。

```php
$options = [
    'cost' => 13
];
$password_hash = password_hash($password, PASSWORD_BCRYPT, $options);

$cipher = "aes-１２８-cbc";
$iv_len = openssl_cipher_iv_length($cipher);
$iv = random_bytes($iv_len);
$encrypt = openssl_encrypt($password_hash, $cipher, $pepper, 0, $iv);
```

pepperを付与してハッシュ化するよりは、共通鍵暗号で暗号化してしまう方が、長期的な保管に向いていると思います。

# まとめ
一口にハッシュ化と言っても方法は色々あります。安全に保管するためにはその関数も重要になります。また、以前は、MD5やSHA-1なんかが使われていたように、数年するとベストな関数も変わります。必ず、その時のベストな関数を選択するようにしましょう。

# 参考
https://owasp.org/www-project-application-security-verification-standard/
https://qiita.com/prt445/items/42856a66666aae65a16e
https://pages.nist.gov/800-63-3/sp800-63b.html
https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
https://qiita.com/shioshiota/items/d439e63c4ee651d956ab