如何从JSON获取相同的哈希

我需要对JSON签名,但是我发现解组编组可以更改JSON的顺序,这可能会使签名无效。 </ p>

尽管有顺序,是否仍然可以从JSON字符串中产生相同的哈希值?</ p>

我看过JOSE却无法 找到实际上散列JSON的函数。</ p>
</ div>

展开原文

原文

I need to sign a JSON but I noticed that unmarshaling/marshaling can change JSON's order which might make the signature invalid.

Is there anyway to produce the same hash from a JSON string despite its order?

I've had a look at JOSE but couldn't find the function that actually hashes JSON.

doujieyu7062
doujieyu7062 是的,由于签名签名/验证包括对消息进行哈希处理,因此您最好遵循该想法。这已经过了很好的测试,并且与签名对称。只需将签名替换为哈希值即可。您可能只需要查找现有的签名应用程序并跳过签名计算:只需将哈希值设为64。
一年多之前 回复
dou70260
dou70260 要验证签名的消息,您不需要执行解组。签名在base64url中编码的JSON字符串上进行,验证直接在base64上完成。仅当验证正确时,才对消息进行解码并进行解组。这就是JWS(JsonWeb签名)标准的工作方式。验证后,节点的顺序并不重要
一年多之前 回复
doujubeng2942
doujubeng2942 好的,我知道了。谢谢
一年多之前 回复
dsdt66064367
dsdt66064367 是的,这是真的。重新封送和再次封送可能会有所不同。我的意思是,仅使用encoding/json封送,输出将是确定性的/相同的。至少如果使用相同的Go版本。
一年多之前 回复
doubutao6216
doubutao6216 但是,如果他们先将某些内容编组到地图中,然后再将其编组到json的情况下,则不能保证编组的输出与解组的输入相同,例如原始输入的键未排序。不知道是不是OP看到订单不一致的情况。
一年多之前 回复
duanpei4455
duanpei4455 从Go1.12+开始的IFAK(地图值,它将自动按键排序)
一年多之前 回复
duangai1368
duangai1368 即使使用映射,输出也是确定性的:“对映射键进行排序并用作JSON对象键...”因此,总的来说,如果您不使用自定义封送处理程序来破坏顺序,则输出应该是确定性的。
一年多之前 回复
dongtan8532
dongtan8532 您正在使用哪个版本的go?
一年多之前 回复
dtutlamjasblef7982
dtutlamjasblef7982 因此,如果我再次进行元帅,元帅和元帅,它将产生相同的命令吗?我会测试
一年多之前 回复
dongmei8460
dongmei8460 如果避免使用地图,则应该能够保留顺序。
一年多之前 回复

1个回答

JOSE JWS will absolutely do what you want at the cost of having to manage keys for signatures and verification.

But let's assume that you don't really need the whole key management stuff and general crypto functionality in JOSE and you're not SUPER concerned about performance (so a little string mangling in this process is OK).

You could dumbly unmarshal your JSON and re-marshal it, then just hash that:

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
", hash(DOCA))
    fmt.Println(DOCB)
    fmt.Printf("Hash: %s
", hash(DOCB))
}

The output of this program (at least in the golang docker container) is:

{ "foo": 1.23e1, "bar": { "baz": true, "abc": 12 } }
Hash: d50756fbb830f8335187a3f427603944c566772365d8d8e6f6760cd2868c8a73
{ "bar": { "abc": 12, "baz": true }, "foo": 12.3 }
Hash: d50756fbb830f8335187a3f427603944c566772365d8d8e6f6760cd2868c8a73

The nice thing about this approach is that, for the cost of some performance, you get insulated from whatever dumb junk you did while marshalling your JSON in the first place (so, unlike other suggestions, you don't have to think about what you might be doing with custom Marshallers and whatnot). This is especially a big deal when you forget that this was an issue at all in version 3.8 of your code a year from now, implement something that messes with the marshal order, and start breaking things.

And, of course, you could always add the hash to the resulting struct and marshal again with the extra item in the map. Obviously you want to optimize a bit for performance if you're worried about it at all and properly handle errors, but this is a good prototype anyway :-)

Oh, and if you're super-worried about edge cases biting you, you could also use canonical JSON to marshal, since it's specifically designed for this type of use (though, honestly, I couldn't come up with an example in my testing where c-json worked but go's default json didn't).

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐