Java — Подписание объектов JSON

Я должен обмениваться объектами JSON между различными платформами и реализациями сервиса и делать его целостность проверяемой с помощью цифровых подписей. Таким образом, платформа A создаст такой объект и создаст цифровую подпись. Затем указанная подпись включается в объект и отправляется на платформу B. Объекты JSON могут содержать произвольные атрибуты и данные.

Например. в PHP:

function signObject($jsonObjectToSign, $privateKey) {
$jsonObjectToSign->signature = "";
$msgToSign = json_encode($jsonObjectToSign);

openssl_sign($msgToSign, $jsonObjectToSign->signature, $privateKey, OPENSSL_SLGO_SHA1);

return $jsonObjectToSign;
}

Проблема в том, что, например, в Java нет способа определить, будут ли атрибуты объекта JSON в том же порядке, в котором вы их добавили (через JSONObject.put ()). Итак, если я сделаю

$json = json_encode('{"a":1, "b":2}');

в PHP подпишите этот объект, как указано выше, перенесите его на сервер, основанный на Java, декодируйте объект json, а затем попытайтесь проверить подпись, возможно, я получу другой порядок атрибутов объекта.

Так что мне нужен надежный способ создания String из JSONObject, независимо от используемого языка или платформы.

Приведенный выше пример объекта должен всегда выводиться {"a":1, "b":2} и никогда {"b":2, "a":1}, К сожалению, это обычный случай, например на Яве.

Существуют ли «лучшие практики» для безопасной подписи объектов JSON?

Но позвольте мне описать проблему по-другому:

Допустим, я хочу сделать это на Java (или любом другом языке):

JSONObject j = new JSONObject();
j.put("a", 1);
j.put("b", 2);

Теперь мне нужна функция сериализации, которая выводит всегда одно и то же строковое представление для этого объекта, независимо от того, как и на каком языке этот объект создается.

6

Решение

Подписание и шифрование объектов JSON определено в наборе спецификаций JOSE, где JOSE означает Подписание и шифрование объектов Javascript, см. http://jose.readthedocs.org/en/latest/ JOSE использует отдельную сигнатуру, вычисленную по представлению кодирования base64url объекта JSON. Подпись не является частью самого объекта JSON, поэтому для ее проверки не требуется переупорядочение.

3

Другие решения

Поскольку у AFAIK еще нет официального (или неофициального) стандарта на подпись JSON, я бы, вероятно, сделал пользовательскую реализацию. Я бы определил новый объект JSON, например

{
"original": "..." // original JSON as a Base64 encoded string
"signature": "..." // the signature
}

и внедрить слой подписи / проверки подписи на обеих сторонах моей системы.

2

Вот как я решил это сейчас. Это похоже на то, что делает JOSE, за исключением заголовка. Но JOSE, кажется, приносит много накладных расходов (и возможностей), которые мне не нужны. Поэтому я решил пойти со следующим:

class Signature
{
private static $algorithm = OPENSSL_ALGO_SHA512;
private static $signaturePrefix = '-----BEGIN SIGNATURE-----';
private static $signaturePostfix = '-----END SIGNATURE-----';

public static function createSignature($message, $privateKey)
{
$signature = null;

openssl_sign($message, $signature, $privateKey, self::$algorithm);

return self::$signaturePrefix . base64_encode($signature) . self::$signaturePostfix;
}

public static function verifySignature($message, $publicKey, $signature)
{
$signature = str_replace(self::$signaturePrefix, '', $signature);
$signature = str_replace(self::$signaturePostfix, '', $signature);

return openssl_verify($message, base64_decode($signature), $publicKey, self::$algorithm);
}

public static function signJSON($jsonToSign, $privateKey)
{
if(gettype($jsonToSign) != 'string')
$jsonToSign = json_encode($jsonToSign);

$signedJSON = json_decode('{}');
$sigedJSON->signature = self::createSignature($message, $privateKey);
$signedJSON->object = $jsonToSign;

return $signedJSON;
}

public static function verifyJSONSignature($jsonObject, $publicKey)
{
if(gettype($jsonObject->object) == 'string')
throw new Exception('Value $jsonObject->object must be a String, is a ' . gettype($jsonObject->object));

return self::verifySignature($jsonObject->object, $publicKey, $jsonObject->signature);
}
}
0

JsonObject js = new JsonObject();
js.addProperty("c", "123");
js.addProperty("t", "yyyy-MM-dd'T'HH:mm:ss.SSSZ");
System.out.println("Json object == " + js);
GenerateSignature util = new GenerateSignature();
String ecodedToken = util.signJSONObject(js);
-1

Мы столкнулись с аналогичной проблемой с хэшированием JSON-кодированных полезных нагрузок. В нашем случае мы используем следующую методологию:

  1. Конвертировать данные в объект JSON
  2. Кодировать полезную нагрузку JSON в base64
  3. Дайджест сообщения (HMAC) сгенерированной полезной нагрузки base64
  4. передать полезную нагрузку base64 (с созданной подписью).

Подробности смотрите в ссылке ниже

связанный ответ здесь:
Как криптографически хешировать объект JSON?

-1
По вопросам рекламы [email protected]