Ошибка «Неправильные символы UTF-8» при попытке использовать json_encode и массив, содержащий некоторые зашифрованные значения - PullRequest
1 голос
/ 15 июня 2019

Мне нужно отправить некоторые данные JSON на конечную точку API, которая требует шифрования частей запроса.У меня есть открытый ключ, который был предоставлен мне провайдером API.Вот соответствующий фрагмент кода:

$key = "-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END PUBLIC KEY-----";

openssl_public_encrypt('my_username', $username, openssl_pkey_get_public($key));
openssl_public_encrypt('my_pa55w0rd', $password, openssl_pkey_get_public($key));

$client = new GuzzleHttp\Client();
$result = $client->post(
    'https://api.domain.com/endpoint',
    [
        'headers' => [
            'Authorization' => 'Bearer ' . $bearerToken,
            'Content-Type' => 'application/json',
        ],
        'json' => [
            'username' => $username,
            'pasword' => $password,
            'unencrypted_key' => 'an unencrypted value,
        ]
    ]
);

Приведенный выше фрагмент кода дает мне ошибку json_encode error: Malformed UTF-8 characters, possibly incorrectly encoded.При выполнении echo $username; я вижу, что в выводимой строке есть куча искаженных символов: malformed encrypted string

Я не уверен, что делаю неправильно или есть какие-то другиеПодход, который я должен использовать для шифрования значений до того, как они будут закодированы в формате json.

ПРИМЕЧАНИЕ: Хотя я не использую функцию json_encode в моем коде выше, я считаю, что HTTP-библиотека жрет1016 * s массив перед отправкой запроса.

1 Ответ

3 голосов
/ 19 июня 2019

Как отмечается в комментарии msg :

openssl_public_encrypt возвращает двоичный поток, это искаженный вывод, вам нужно сначала закодировать его в ascii, вероятно, с помощьюbase64_encode но зачем вам шифрование, если транспорт уже использует ssl?Проверьте с провайдером API.

Однако возможно также, что они ожидают данные в шестнадцатеричном формате.Вместо этого попробуйте bin2hex().

Если у них есть какой-то другой странный формат (Base32Hex?), Не стесняйтесь использовать эту библиотеку RFC 4648 для кодирования ваших сообщений.


Важная информация о безопасности

Это не ответ на ваш вопрос, но вы и ваш API должны знать об этом.

openssl_public_encrypt по умолчанию RSA сЗаполнение PKCS # 1 v1.5, уязвимое для атаки оракула заполнения .

Как минимум: разработчик API, с которым вы общаетесь, должен прекратить принимать данные, зашифрованные с помощью RSAс дополнением PKCS # 1v1.5 и вместо этого принимают только шифротексты OAEP.

Существует способов обойти атаку Блейхенбахера 1998 года , но они беспорядочные и могут быть толькорешается на уровне протокола, а не на уровне библиотеки или примитива.

Однако шифрование RSA является грязным по другим причинам: Вы не можете зашифровать большие сообщения напрямую с помощью RSA .

Есть также пленЕсть и другие причины, по которым RSA может пойти не так .

Рекомендация

Лучшее решение - полностью прекратить использование RSA.

Libsodium имеет привязки в самых популярныхязыки программирования (и включены в ядро ​​PHP 7.2) и облегчают получение правильной информации .

// On your end...
$sendToProvider = sodium_bin2hex(
    sodium_crypto_box_seal($privateData, $publicKey)
);

// On their end...
$decrypted = sodium_crypto_box_seal_open(
    sodium_hex2bin($encrypted),
    $keypair
);

Вы могли бы столкнуться с проблемой кодирования в любом случае (так как обаAPI возвращают необработанные двоичные строки).Однако использование libsodium обошло бы тонну проблем безопасности, о которых вы, вероятно, не знали, пока не прочитали этот ответ StackOverflow.

Кроме того: не расстраивайтесь, если не знаете.Ты не одинок.Даже криптографическая библиотека Zend Framework столкнулась с этими уязвимостями RSA , и в их команде был Энрико Зимуэль.RSA - просто плохой выбор для криптографии в реальном мире.

...