Случайное исключение RuntimeException: единственными поддерживаемыми шифрами являются AES-128-CBC и AES-256-CBC с правильной длиной ключа

У меня такая же проблема с Laravel 5.3 (на сервере Windows). Я сделал все возможные попытки: проверить файл .env, config, новое поколение ключей artisan, кеш: очистить, настроить: очистить, добавить композитор, но проблема случайным образом сохраняется.

Обратите внимание, что тот же код с точно такой же версией apache, mysql, php, не создает эту проблему в Mac OS.

Я обнаружил, что ключ (первый параметр Encrypter constractor) приходит "иногда" пустым, и, конечно, он терпит неудачу. В большинстве случаев ключ является правильным, но случайным образом ключ прибывает пустым из EncryptionServiceProvider, который по очереди запрашивает его в конфигурации приложения.

Таким образом, единственным решением, которое сработало для меня, было добавить if ($key) в EncryptionServiceProvider, чтобы конструктор шифрования не вызывался с пустым ключом.

Конечно, это не "чистое" решение, и оно не объясняет проблему, но, по крайней мере, позволяет найти файл журнала, заполненный ошибкой:

RuntimeException: единственными поддерживаемыми шифрами являются AES-128-CBC и AES-256-CBC и страницы отображаются правильно.

Если это ошибка Laravel, я не знаю, но, конечно, если кто-то может это объяснить, я буду более счастлив узнать.

Ниже мой модифицированный класс: я просто добавил строку if ($key) до new Encrypter:

class EncryptionServiceProvider extends ServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    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 = $config['key'], 'base64:')) {
                $key = base64_decode(substr($key, 7));
            }
        if ($key)
            return new Encrypter($key, $config['cipher']);
        });
    }
}

Дополнительная информация и журнал возврата:

Конечно, по мере того как я писал, я проверил файл .env, конфигурацию, новое поколение ключей artisan, cache: clear, config: clear, composer update. Этот материал в порядке, так как он работает 99% времени, но случайно я получаю ошибку.

Здесь обратная трассировка:

[2017-01-09 10:25:40] test.ERROR: RuntimeException: поддерживается только поддержка Шифрами являются AES-128-CBC и AES-256-CBC с правильной длиной ключа. в C:\Apache24\HTDOCS\сф\поставщика\Laravel\рамки\SRC\Осветите\Encryption\Encrypter.php: 43

Трассировка стека:

#0 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Encryption\EncryptionServiceProvider.php(27): Illuminate\Encryption\Encrypter->__construct('', 'AES-256-CBC')
#1 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(746): Illuminate\Encryption\EncryptionServiceProvider->Illuminate\Encryption\{closure}(Object(Illuminate\Foundation\Application), Array)
#2 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(644): Illuminate\Container\Container->build(Object(Closure), Array)
#3 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Application.php(709): Illuminate\Container\Container->make('encrypter', Array)
#4 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(864): Illuminate\Foundation\Application->make('encrypter')
#5 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(819): Illuminate\Container\Container->resolveClass(Object(ReflectionParameter))
#6 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(788): Illuminate\Container\Container->getDependencies(Array, Array)
#7 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Container\Container.php(644): Illuminate\Container\Container->build('App\\Http\\Middle...', Array)
#8 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Application.php(709): Illuminate\Container\Container->make('App\\Http\\Middle...', Array)
#9 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(127): Illuminate\Foundation\Application->make('App\\Http\\Middle...')
#10 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#11 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\View\Middleware\ShareErrorsFromSession.php(49): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#12 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(137): Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#13 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#14 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Session\Middleware\StartSession.php(64): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#15 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(137): Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#16 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#17 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse.php(37): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#18 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(137): Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#19 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#20 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(104): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#21 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Router.php(655): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#22 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Router.php(629): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#23 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Router.php(607): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#24 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(268): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#25 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(53): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}(Object(Illuminate\Http\Request))
#26 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode.php(46): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#27 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(137): Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure))
#28 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Routing\Pipeline.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#29 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php(104): Illuminate\Routing\Pipeline->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#30 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(150): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#31 C:\Apache24\htdocs\sph\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php(117): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#32 C:\Apache24\htdocs\sph\public\index.php(53): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#33 {main}  

Ответы

Ответ 1

Проблема возникает при использовании поточно-безопасных версий PHP на многопоточных веб-серверах вместо многопроцессорных веб-серверов. Вы можете прочитать о проблеме немного подробнее о проблема Github здесь, Github здесь, а отчет об ошибке PHP здесь. Есть еще несколько ссылок, но они просто отделены от тех немногих, что я опубликовал.

Основной смысл заключается в том, что с многопоточным веб-сервером у вас есть один процесс, который обрабатывает несколько потоков. Однако методы putenv()/getenv() не являются потокобезопасными и изменяют переменные среды на уровне процесса, поэтому затрагиваются все потоки под этим процессом.

Итак, у вас получилось что-то вроде этого: (как описано в этой проблеме):

Request 1: {starts --- loads env --- work --- finishes}
Request 2:                             {starts ----- loads env --- work --- finishes}

Итак, запрос 1 входит, загружает среду и работает. Пока запрос 1 работает, запрос 2 входит и запускается в другом потоке. Перед запросом 2 читает переменные среды, запрашивает 1 финиширует, а PHP очищает все переменные, заданные putenv(). Теперь попросите 2 попытки прочитать среду, но получает null, потому что переменные были очищены при завершении запроса 1.

Эта проблема может быть смягчена двумя способами:

  • Не используйте файл .env. Задайте переменные среды напрямую и отключите phpdotenv. Это также предлагается пакетом :

    phpdotenv предназначен для среды разработки и обычно не должен использоваться в производстве. В процессе производства фактические переменные среды должны быть установлены так, чтобы не было накладных расходов на загрузку файла .env для каждого запроса.

  • Никогда не используйте метод env() вне файлов конфигурации и убедитесь, что вы кешируете свои файлы конфигурации. Используя этот метод, среда читается один раз: при создании кеша конфигурационного файла. Каждый фактический веб-запрос будет считывать данные из кеша, а переменные окружения никогда не будут затронуты снова.

Ответ 2

Я установил Laravel 5.3, и я не нашел там файл .env. И бум... Это была проблема. Я создал файл .env в корневом каталоге приложения и запустил

php artisan key: generate

в терминале, и он сгенерировал строку с кодировкой base 64 в терминале. Скопируйте эту строку в .ENV файл как

APP_KEY = base64: ******************************************* *****

где **** генерируется закодированная строка. Запустите приложение еще раз, и оно должно работать.

Ответ 3

Это так просто, скопируйте файл APP_KEY из .env в config/app.php -> key или выполните следующую команду:

php artisan key:generate