我需要对JSON进行签名,但我发现解组/编组可以更改JSON的顺序,这可能会使签名无效。
不管顺序如何,是否仍然可以从JSON字符串中产生相同的哈希值?
我看过JOSE,但找不到真正散列JSON的函数。
答案 0 :(得分:0)
JOSE JWS绝对会做您想要做的事情,而不必管理签名和验证的密钥。
但是,假设您实际上并不需要JOSE中的全部密钥管理内容和常规的加密功能,并且您也不是超级担心性能(因此在此过程中进行一些字符串操作就可以了)。
您可以笨拙地解组JSON并重新将其编组,然后只需对它进行散列即可:
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
json "encoding/json"
)
// NB These docs are strictly-speaking the same.
const DOCA = "{ \"foo\": 1.23e1, \"bar\": { \"baz\": true, \"abc\": 12 } }"
const DOCB = "{ \"bar\": { \"abc\": 12, \"baz\": true }, \"foo\": 12.3 }"
func hash(doc string) string {
// Dumb af, but it's a cheap way to specific the most generic thing
// you can :-/
var v interface{}
json.Unmarshal([]byte(doc), &v) // NB: You should handle errors :-/
cdoc, _ := json.Marshal(v)
sum := sha256.Sum256(cdoc)
return hex.EncodeToString(sum[0:])
}
func main() {
fmt.Println(DOCA)
fmt.Printf("Hash: %s\n", hash(DOCA))
fmt.Println(DOCB)
fmt.Printf("Hash: %s\n", hash(DOCB))
}
该程序的输出(至少在golang docker容器中)为:
{ "foo": 1.23e1, "bar": { "baz": true, "abc": 12 } }
Hash: d50756fbb830f8335187a3f427603944c566772365d8d8e6f6760cd2868c8a73
{ "bar": { "abc": 12, "baz": true }, "foo": 12.3 }
Hash: d50756fbb830f8335187a3f427603944c566772365d8d8e6f6760cd2868c8a73
这种方法的好处是,为了提高性能,您首先将JSON编组为JSON时,就可以避免做任何笨拙的垃圾(因此,与其他建议不同,您不必考虑关于您可能会使用自定义编组器做什么以及其他操作)。当您忘记从一年以后的代码版本3.8中根本就没有这个问题,实施与元帅命令混乱的事情并开始破坏事情时,这尤其重要。
当然,您始终可以将哈希添加到生成的结构中,并使用地图中的多余项再次编组。显然,如果您完全担心并可以正确处理错误,则希望对性能进行一些优化,但这仍然是一个很好的原型:-)
哦,如果您担心边缘情况会咬伤您,您还可以使用canonical JSON进行编组,因为它是专门为这种类型的使用而设计的(不过,老实说,我不能在我的测试中举了一个例子,其中c-json起作用,但是go的默认json没有起作用。