Как расшифровать данные, зашифрованные с помощью crypto-js, в laravel?

У меня есть этот фрагмент кода в моем js:

export const encrypt = (data, key) => {
    const encrypted = CryptoJS.AES.encrypt(
        JSON.stringify(data),
        key
    ).toString();
    return encrypted;
};

но когда я расшифровываю его в своем бэкэнде Laravel:

Route::post('/decrypt', function (Request $request) {
    try{
        $encrypted = $request->input("data");
        Crypt::decrypt($encrypted);
    }
    catch(DecryptException $e) {
        dd("error", $e);
    }
});

это дает мне DecryptException «Полезная нагрузка недействительна»

зависит от того, как вы шифруете данные, что такое data и одинаков ли ключ с обеих сторон

kris gjika 23.07.2024 17:15

Вопрос: Почему вы хотите/необходимо шифровать данные между интерфейсом (браузером) и сервером (сервером)? Если вам нужна безопасность, вы можете просто использовать HTTPS — это автоматически зашифрует весь трафик между браузером и вашим веб-сервером, а не только отдельные фрагменты данных.

ADyson 23.07.2024 17:22

Для расшифровки с помощью Crypt::decrypt() из PHP/Laravel логика шифрования CryptoJS должна имитировать логику шифрования PHP/Laravel. Вы можете найти последнее, например. вот . Как вы можете видеть, ваш текущий код CryptoJS несовместим, например. MAC отсутствует и формат отличается (PHP/Laravel: строка JSON в кодировке Base64, содержащая зашифрованный текст, IV и MAC).

Topaco 23.07.2024 17:59

Вы передаете ключ клиенту?

gre_gor 26.07.2024 22:06

@gre_gor, что ты имеешь в виду, говоря о передаче ключа клиенту? Потому что я поместил ключ в оба конца файла .env.

marouane ebourk 29.07.2024 11:08

@ADyson Я просто пробовал что-то новое, действительно ли нет необходимости добавлять шифрование в качестве еще одного уровня безопасности?

marouane ebourk 29.07.2024 11:09

@marouaneebourk, если только ваши данные по какой-то причине не являются действительно сверхконфиденциальными (например, правительственная тайна, очень конфиденциальные личные данные или что-то еще, регулируемое специальным законодательством, требующим дополнительной безопасности), то почти наверняка нет. HTTPS должно быть достаточно для подавляющего большинства случаев.

ADyson 29.07.2024 11:16

@marouaneebourk, что именно вы подразумеваете под «я вставил ключ в оба конца файла .env»? Оба конца чего? Похоже, что один конец представляет собой сценарий Javascript. Обычно это работает в браузере, где нельзя хранить секреты. Вы хотите сказать, что это на самом деле скрипт nodeJS, работающий на сервере? Пожалуйста, сделайте это на 100% ясным в своем вопросе, потому что такие различия могут быть значительными.

ADyson 29.07.2024 11:20

@ADyson, когда я сказал оба конца, я имел в виду интерфейс и серверную часть, поскольку мой laravel .env не читается, но в моем пакете реагирования я не знаю, как именно все работает (я все еще новичок)

marouane ebourk 29.07.2024 11:45

Все, что попадает в браузер, может быть прочитано конечным пользователем, если он знает это, а также, возможно, расширениями браузера и т. д., в зависимости от предоставленных разрешений. Поэтому вставлять туда ключ небезопасно. Но вы до сих пор не подтвердили, используется ли ваш JS в браузере или нет.

ADyson 29.07.2024 12:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
10
103
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Что ж... мир шифрования чрезвычайно сложен, поэтому никогда не принимайте ничего как должное. Хотя шифрование/дешифрование с помощью одного и того же инструмента несколько тривиально, выполнение одного и того же в разных системах может оказаться весьма затруднительным.

Здесь, если все элементы на месте (правильная установка, правильная конфигурация...!), проблема может заключаться в data или key.

Ключ

Как отметил @Kris, вам следует проверить, «одинаков ли ключ с обеих сторон». На первый взгляд это может показаться очевидным... но на самом деле это не так.

По сути, перед шифрованием/дешифрованием CryptoJS сначала проверяет, является ли «ключ» реальным ключом или открытым текстовым паролем (называемым парольной фразой). В последнем случае он преобразует открытый текстовый пароль в ключ, а затем обрабатывает данные. Опять же... какой тип преобразования? Ключу какой длины? Все зависит от вашей конфигурации и настроек по умолчанию вашей версии. Обычно размер ключа по умолчанию составляет 256.

Я не вижу никаких настроек пароля в вашем примере с серверной частью, но вам следует проверить, обрабатывает ли он ключ точно так же, как это делает CryptoJS. Если у вас есть контроль, вы можете попытаться воспроизвести в серверной части точное поведение CryptoJS с ключом. Но выполнение преобразования самостоятельно может значительно сэкономить время, предоставив CryptoJS реальный ключ, который он не будет пытаться обработать.

Данные

Зашифрованные данные обычно являются двоичными и не подходят для транспортировки. Существует множество форм безопасной передачи данных, и одной из наиболее широко используемых является BASE64. На самом деле это то, во что CryptoJS преобразует данные при использовании toString(), как вы это делаете.

Теперь вам нужно проверить, что ваш сервер ожидает этот формат и правильно с ним работает, как в интерфейсе, так и в процедуре дешифрования. Например, если Crypt::decrypt() ожидает двоичные данные, вам следует сначала декодировать полученные данные BASE64.

Ответ принят как подходящий

Похоже, вы столкнулись с проблемой, поскольку методы шифрования и библиотеки, которые вы используете в JavaScript и Laravel, по умолчанию несовместимы. CryptoJS.AES.encrypt и Crypt::decrypt в Laravel используют разные конфигурации и алгоритмы по умолчанию. Вот несколько моментов, которые помогут обеспечить совместимость между вашими методами шифрования JavaScript и Laravel:

Согласованные параметры шифрования. Убедитесь, что JavaScript и Laravel используют одни и те же параметры шифрования (алгоритм, режим, заполнение и т. д.). По умолчанию CryptoJS.AES.encrypt использует режим CBC и заполнение PKCS7. Фасад Laravel Crypt также использует режим AES-256-CBC и заполнение PKCS7, но для этого требуется определенный размер и конфигурация ключа.

Убедитесь, что ключ, используемый в JavaScript, соответствует ключу, используемому в Laravel, и что вы правильно управляете IV (вектором инициализации). Метод CryptoJS.AES.encrypt также может потребовать указания IV. В Laravel фасад Crypt обрабатывает IV внутри себя, но в специальной реализации вам придется управлять IV вручную.

Кодирование: убедитесь, что данные правильно кодируются и декодируются между системами. CryptoJS выводит строки в кодировке Base64, а Laravel также ожидает кодировку Base64.

Я думаю, что ниже должно помочь:

export const encrypt = (data, key) => {
    // Ensure your key is 32 bytes for AES-256
    const keySize = 256 / 32;
    const keyHex = CryptoJS.enc.Hex.parse(key);
    const iv = CryptoJS.lib.WordArray.random(16); // Random 16 bytes IV

    const encrypted = CryptoJS.AES.encrypt(
        JSON.stringify(data),
        keyHex,
        { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }
    );

    // Encode both the IV and the encrypted data
    return `${iv.toString(CryptoJS.enc.Base64)}:${encrypted.toString()}`;
};

Расшифровка Ларавел

Route::post('/decrypt', function (Request $request) {
    try {
        // Extract the IV and encrypted data
        $data = $request->input('data');
        list($iv, $encrypted) = explode(':', $data, 2);

        // Decode the Base64 encoded values
        $iv = base64_decode($iv);
        $encrypted = base64_decode($encrypted);

        // Your key should be 32 bytes for AES-256
        $key = env('AES_KEY'); // Ensure this key matches the one used in JavaScript

        // Decrypt using openssl
        $decrypted = openssl_decrypt(
            $encrypted,
            'aes-256-cbc',
            $key,
            OPENSSL_RAW_DATA,
            $iv
        );

        return response()->json(['data' => json_decode($decrypted, true)]);
    } catch (DecryptException $e) {
        return response()->json(['error' => 'Decryption failed'], 400);
    }
});

Большое спасибо за этот ответ, та часть, где вы упомянули отступы и режим, помогла мне больше всего.

marouane ebourk 25.07.2024 13:59

Напоминание: ответы, созданные с помощью инструментов искусственного интеллекта, не допускаются в Stack Overflow. Узнать больше

miken32 26.07.2024 18:57

Это функция, которая работала у меня с функцией Crypt::decrypt в laravel. вам просто нужно отключить десериализацию

export function encrypt(data, key) {
    let iv = CryptoJS.lib.WordArray.random(16),
        generatedKey = CryptoJS.enc.Base64.parse(key);
    let options = {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7,
    };
    let encrypted = CryptoJS.AES.encrypt(
        JSON.stringify(data),
        generatedKey,
        options
    );
    encrypted = encrypted.toString();
    iv = CryptoJS.enc.Base64.stringify(iv);
    let result = {
        iv: iv,
        value: encrypted,
        mac: CryptoJS.HmacSHA256(iv + encrypted, generatedKey).toString(),
    };
    result = JSON.stringify(result);
    result = CryptoJS.enc.Utf8.parse(result);
    result = CryptoJS.enc.Base64.stringify(result);
    return result;
}
private function decryptValue($value)
    {
        try {
            return json_decode(Crypt::decrypt($value, false), true);
        } catch (\Exception $e) {
            throw new DecryptException('Decryption failed: ' . $e->getMessage());
        }
    }

Другие вопросы по теме