签署 JSON 个对象
Signing JSON objects
我必须在不同平台和服务实现之间交换 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}');
in PHP,如上所述签署这个对象,将其传输到基于 java 的服务器,解码 json 对象然后尝试验证签名,我会可能得到对象属性的不同顺序。
所以我需要的是一种从 JSON对象创建字符串的可靠方法,与使用的语言或平台无关。
上面的示例对象需要始终输出 {"a":1, "b":2}
而从不输出 {"b":2, "a":1}
。不幸的是,这是常见的情况,例如在 Java.
有没有"best practice"以安全的方式签署JSON对象?
但让我用另一种方式来描述这个问题:
假设我想用 Java(或任何其他语言)执行此操作:
JSONObject j = new JSONObject();
j.put("a", 1);
j.put("b", 2);
现在,我需要一个序列化函数,它始终为该对象输出相同的字符串表示形式,无论该对象是如何创建的以及使用何种语言创建的。
由于 AFAIK 还没有关于 JSON 签名的官方(既非官方)标准,我可能会做一个自定义实现。我会定义一个新的 JSON 对象,例如
{
"original": "..." // original JSON as a Base64 encoded string
"signature": "..." // the signature
}
并在我系统的 both/all 端实施签名/签名验证层。
JSON 对象的签名和加密在 JOSE 规范套件中指定,其中 JOSE 代表 Javascript 对象签名和加密,请参阅 http://jose.readthedocs.org/en/latest/ JOSE 使用独立签名计算JSON 对象的 base64url 编码表示。签名不是 JSON 对象本身的一部分,因此不需要重新排序来验证它。
我现在就是这样解决的。除了 header 之外,它与 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);
}
}
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);
我们在散列 JSON-encoded 有效载荷时遇到了类似的问题。在我们的案例中,我们使用以下方法:
- 将数据转换成JSON对象
- 在 base64 中编码 JSON 有效负载
- 消息摘要 (HMAC) 生成的 base64 负载
- 传输 base64 负载(带有生成的签名)。
详情见下方link
link在这里回答:
How to cryptographically hash a JSON object?
我必须在不同平台和服务实现之间交换 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}');
in PHP,如上所述签署这个对象,将其传输到基于 java 的服务器,解码 json 对象然后尝试验证签名,我会可能得到对象属性的不同顺序。
所以我需要的是一种从 JSON对象创建字符串的可靠方法,与使用的语言或平台无关。
上面的示例对象需要始终输出 {"a":1, "b":2}
而从不输出 {"b":2, "a":1}
。不幸的是,这是常见的情况,例如在 Java.
有没有"best practice"以安全的方式签署JSON对象?
但让我用另一种方式来描述这个问题:
假设我想用 Java(或任何其他语言)执行此操作:
JSONObject j = new JSONObject();
j.put("a", 1);
j.put("b", 2);
现在,我需要一个序列化函数,它始终为该对象输出相同的字符串表示形式,无论该对象是如何创建的以及使用何种语言创建的。
由于 AFAIK 还没有关于 JSON 签名的官方(既非官方)标准,我可能会做一个自定义实现。我会定义一个新的 JSON 对象,例如
{
"original": "..." // original JSON as a Base64 encoded string
"signature": "..." // the signature
}
并在我系统的 both/all 端实施签名/签名验证层。
JSON 对象的签名和加密在 JOSE 规范套件中指定,其中 JOSE 代表 Javascript 对象签名和加密,请参阅 http://jose.readthedocs.org/en/latest/ JOSE 使用独立签名计算JSON 对象的 base64url 编码表示。签名不是 JSON 对象本身的一部分,因此不需要重新排序来验证它。
我现在就是这样解决的。除了 header 之外,它与 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);
}
}
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);
我们在散列 JSON-encoded 有效载荷时遇到了类似的问题。在我们的案例中,我们使用以下方法:
- 将数据转换成JSON对象
- 在 base64 中编码 JSON 有效负载
- 消息摘要 (HMAC) 生成的 base64 负载
- 传输 base64 负载(带有生成的签名)。
详情见下方link
link在这里回答: How to cryptographically hash a JSON object?