1. yk2220s

    No comment

    yk2220s
Changes in body
Source | HTML | Preview
@@ -44,11 +44,11 @@
```
という風に生成されています。 `random_bytes` はphp7から追加された、ランダムバイトを生成する関数です。([技術自体](https://github.com/paragonie/random_compat)はphp5.xからでも使えたみたいです。)
つまり実際は `base64_encode(random_bytes(32))` が実行されています。
実際に実行してみたら `nnxsf4WwqhHKhwgx7sLjwhEl0DqsBUMpffCmTlvh+CE=` このように無事出力されました。
-# APP_KEY の使用され方
+# APP_KEY の使用され方 (PasswordBroker編)
そして、実際に生成されたAPP_KEYがどのように使われているかを確認してみます。
基本 `config/app.php` 内で `'key' => env('APP_KEY')` と格納されているので、 `config('app.key')` もしくは `['config']['app.key']` などと検索してみて使われてない場所がないかなーと探してみます。
そして引っかかるのが、 `Illuminate\Auth\Passwords\PasswordBrokerManager.php` 。このクラスは`PasswordBroker` を生成するFactoryクラスのようです。
@@ -107,11 +107,129 @@
```
[`hash_hmac`](http://php.net/manual/ja/function.hash-hmac.php)は `HMAC方式を使用してハッシュ値を生成する組み込み関数` です。 第三引数は秘密鍵にあたるので、 token 生成の際の秘密鍵として利用されていたのですね。
このtokenは `PasswordBroker` にてパスワードをリセットする時に発行される Tokenなどとして利用されるようです。
-# 終わりに
+# APP_KEY の使用され方 (Encrypter編)
-最後のほうはだいぶ駆け足になってしまいまたが、 `APP_KEY` がどのように生成され、利用されているかがだいぶ見えてきました。 .. がReadoubleには
+かし他にもReadoubleには
>**アプリケーションキーが設定されていなければ、ユーザーセッションや他の暗号化済みデーターは安全ではありません!**
-あり、パスワードリセット以外にも利用されているはずなので、ほかにも調査次第追記したいと思います! (もしご存知の方いたらご教授いただければ幸いです!)
+書かれています。さすがにここだけではないはず。
+
+そこで実際、暗号化周りのクラスを見てみましょう。
+
+```php:Illuminate/Encryption/Encrypter.php
+
+class Encrypter implements EncrypterContract
+{
+ // doc 略
+ protected $key;
+
+ protected $cipher;
+
+ public function __construct($key, $cipher = 'AES-128-CBC')
+ {
+ $key = (string) $key;
+
+ if (static::supported($key, $cipher)) {
+ $this->key = $key;
+ $this->cipher = $cipher;
+ } else {
+ throw new RuntimeException('The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths.');
+ }
+ }
+
+ // 実装略
+}
+```
+
+この`Encypter`クラスは、コンテナに`encypter`というエイリアスでbindされていて、主にSession、Cookie (csrf tokenなど)などで利用されています。helper `encrypt()` や Facade `Crypt` でも利用されています。つまりLaravelの主要な機能で用いられる暗号化を担うクラスです。
+
+プロパティ `$key` があやしいですね。bindしているProviderを見て見ましょう。
+
+```php:Illuminate/Encryption/EncryptionServiceProvider.php
+class EncryptionServiceProvider extends ServiceProvider
+{
+ // doc 略
+ public function register()
+ {
+ $this->app->singleton('encrypter', function ($app) {
+ $config = $app->make('config')->get('app');
+
+ // If the key starts with "base64:", we will need to decode the key before handing
+ // it off to the encrypter. Keys may be base-64 encoded for presentation and we
+ // want to make sure to convert them back to the raw bytes before encrypting.
+ if (Str::startsWith($key = $this->key($config), 'base64:')) {
+ $key = base64_decode(substr($key, 7));
+ }
+
+ return new Encrypter($key, $config['cipher']);
+ });
+ }
+
+ protected function key(array $config)
+ {
+ return tap($config['key'], function ($key) {
+ if (empty($key)) {
+ throw new RuntimeException(
+ 'No application encryption key has been specified.'
+ );
+ }
+ });
+ }
+}
+```
+
+**見つけました。** `$app['config']['app.key']` のように取得されていないので、検索では引っかかりませんでしたが、
+`$config = $app->make('config')->get('app');` で `config/app.php` の内容を取得し、 `$this->key($config);` で `$config['key']` = `APP_KEY` の内容を取得して `Encrypter` に入れていますね。
+
+脇にそれますが、 `tap($value, $callback)` は5.5から追加されたhelperで、`$value`に対して`$callback`を実行するというものです。
+
+このようにApp_Keyを注入された `Encrypter` で `hash` や `encrypt` メソッドにて (もちろん`decrypt`でも) 利用されています。
+
+```php:Illuminate/Encryption/Encrypter.php
+
+class Encrypter implements EncrypterContract
+{
+ // doc / 一部実装略
+ protected $key;
+
+ protected $cipher;
+
+ public function encrypt($value, $serialize = true)
+ {
+ $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
+ // First we will encrypt the value using OpenSSL. After this is encrypted we
+ // will proceed to calculating a MAC for the encrypted value so that this
+ // value can be verified later as not having been changed by the users.
+ $value = \openssl_encrypt(
+ $serialize ? serialize($value) : $value,
+ $this->cipher, $this->key, 0, $iv
+ );
+ if ($value === false) {
+ throw new EncryptException('Could not encrypt the data.');
+ }
+ // Once we get the encrypted value we'll go ahead and base64_encode the input
+ // vector and create the MAC for the encrypted value so we can then verify
+ // its authenticity. Then, we'll JSON the data into the "payload" array.
+ $mac = $this->hash($iv = base64_encode($iv), $value);
+ $json = json_encode(compact('iv', 'value', 'mac'));
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new EncryptException('Could not encrypt the data.');
+ }
+ return base64_encode($json);
+ }
+
+ protected function hash($iv, $value)
+ {
+ return hash_hmac('sha256', $iv.$value, $this->key);
+ }
+}
+```
+
+# 終わりに
+
+このように `APP_ENV` 暗号化やパスワードリセットといった、セキュリティ的に最重要な箇所で利用されています。アプリケーションのリリース前には一度確認してみてください。
+
+18/5/10
+`# APP_KEY の使用され方 (Encrypter編)` の追加と構成の一部を修正しました。