如何加密哈希JSON对象?

时间:2011-01-12 15:25:40

标签: json cryptography canonicalization

以下问题比最初看起来更复杂。

假设我有一个任意的JSON对象,可能包含任何数量的数据,包括其他嵌套的JSON对象。我想要的是JSON数据的加密哈希/摘要,而不考虑实际的JSON格式本身(例如:忽略换行符和JSON令牌之间的间距差异)。

最后一部分是一项要求,因为JSON将由许多不同平台上的各种(de)序列化程序生成/读取。我知道至少有一个Java的JSON库在反序列化期间读取数据时完全删除了格式。因此,它将打破哈希。

上面的任意数据子句也使事情变得复杂,因为它阻止我以给定顺序获取已知字段并在哈希之前连接它们(大致考虑Java的非加密hashCode()方法是如何工作的。)

最后,将整个JSON字符串散列为一块字节(在反序列化之前)也是不可取的,因为在计算散列时应该忽略JSON中的字段。

我不确定这个问题是否有一个很好的解决方案,但我欢迎任何方法或想法=)

7 个答案:

答案 0 :(得分:43)

对于允许灵活性的任何数据格式计算哈希值时,问题是常见问题。要解决此问题,您需要规范化表示。

例如,Twitter和其他服务用于身份验证的OAuth1.0a协议需要请求消息的安全散列。要计算哈希值,OAuth1.0a表示您需要首先按字母顺序排列字段,按换行符分隔它们,删除字段名称(众所周知),并使用空行表示空值。签名或散列是根据规范化的结果计算的。

XML DSIG以相同的方式工作 - 您需要在签名之前规范化XML。有一个proposed W3 standard covering this,因为它是签名的基本要求。有人称之为c14n。

我不知道json的规范化标准。值得研究。

如果没有,您当然可以为您的特定应用程序使用建立约定。一个合理的开端可能是:

  • 以字典方式按名称对属性进行排序
  • 所有名称上使用的双引号
  • 所有字符串值使用的双引号
  • 名称和冒号之间以及冒号和值之间没有空格或一个空格
  • 值与以下逗号之间没有空格
  • 所有其他空白区域都折叠到一个空格或没有任何内容 - 选择一个
  • 排除您不想签名的任何属性(例如,包含签名的属性)
  • 使用您选择的算法对结果进行签名

您可能还想考虑如何在JSON对象中传递该签名 - 可能会建立一个众所周知的属性名称,例如“nichols-hmac”或其他东西,它会获得hash64的base64编码版本。必须通过散列算法明确排除此属性。然后,JSON的任何接收器都能够检查散列。

规范化表示不需要是您在应用程序中传递的表示形式。只需要在给定任意JSON对象的情况下轻松生成它。

答案 1 :(得分:5)

您可能希望使用bencode,而不是发明自己的JSON规范化/规范化。在语义上它与JSON(数字,字符串,列表和dicts的组合)相同,但具有加密散列所必需的明确编码属性。

bencode用作torrent文件格式,每个bittorrent客户端都包含一个实现。

答案 2 :(得分:4)

这与导致S / MIME签名和XML签名问题的问题相同。也就是说,要签名的数据有多个等效表示。

例如在JSON中:

{  "Name1": "Value1", "Name2": "Value2" }

VS

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032"
}

或者根据您的应用,这甚至可能是等同的:

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032",
    "Optional": null
}

规范化可以解决这个问题,但这是一个你根本不需要的问题。

如果您能够控制规范,那么简单的解决方案就是将对象包装在某种容器中,以防止它被转换为等同的"但是代表性不同。

即。通过不签署"逻辑"来避免这个问题。对象,但改为签署它的特定序列化表示。

例如,JSON Objects - > UTF-8文字 - >字节。将字节标记为字节,然后将它们作为字节发送,例如通过base64编码。由于您要对字节进行签名,因此像空格这样的差异是签名的一部分。

而不是试图这样做:

{  
   "JSONContent": {  "Name1": "Value1", "Name2": "Value2" },
   "Signature": "asdflkajsdrliuejadceaageaetge="
}

这样做:

{
   "Base64JSONContent": "eyAgIk5hbWUxIjogIlZhbHVlMSIsICJOYW1lMiI6ICJWYWx1ZTIiIH0s",
   "Signature": "asdflkajsdrliuejadceaageaetge="

}

即。不要签署JSON,签署编码的 JSON的字节。

是的,这意味着签名不再透明。

答案 3 :(得分:3)

JSON-LD可以进行标准化。

您必须定义上下文。

答案 4 :(得分:1)

RFC 7638:JSON Web密钥(JWK)指纹包括一种规范化。尽管RFC7638期望成员数量有限,但是我们可以对任何成员应用相同的计算。

https://tools.ietf.org/html/rfc7638#section-3

答案 5 :(得分:0)

我会按给定的顺序执行所有字段(例如按字母顺序排列)。为什么任意数据有所不同?你可以迭代属性(ala反射)。

或者,我会考虑将原始json字符串转换为一些定义良好的规范形式(删除所有超级格式化) - 并对其进行散列。

答案 6 :(得分:0)

我们遇到了哈希JSON编码有效负载的简单问题。 在我们的例子中,我们使用以下方法:

  1. 将数据转换为JSON对象;
  2. 在base64中编码JSON有效内容
  3. 消息摘要(HMAC)生成的base64有效负载。
  4. 传输base64有效负载。
  5. 使用此解决方案的优势:

    1. Base64将为给定的有效负载生成相同的输出。
    2. 由于生成的签名将直接从base64编码的有效负载派生,并且由于base64-payload将在端点之间交换,因此我们将确保将保留签名和有效负载。
    3. 此解决方案解决了由于特殊字符的编码差异而出现的问题。
    4. 缺点

      1. 有效载荷的编码/解码可能会增加开销
      2. Base64编码数据通常比原始有效载荷大30%以上。