是否可以保证mgo bson编组保留结构组件的顺序?

时间:2015-07-12 18:50:05

标签: mongodb go bson mgo

我使用mgo在mongo中保存结构。我希望用这个结构(和一个秘密)的散列来保存它们以确定它们是否被篡改(我不希望mongo db本身有秘密)。

目前,我通过使用gob对结构进行序列化来对结构进行哈希处理,结构组件的排序是明确定义的。这很有效,除非我从芒果重新读取结构,事情已经发生了变化 - 确切地说,mongo中的时间值与go相比具有截断的准确性 - 因此散列不匹配。

我计划的工作就是在计算哈希值之前简单地从BSON编组和解组结构,即:

  • Marshal struct to BSON
  • 从BSON解组结构(从而失去精确的时间)
  • Marshall struct to gob和hash的结果[]byte
  • 将hash放在struct
  • 将结构保存到mongo

现在,这有点迂回。

如果我能保证BSON本身始终保留结构中组件的顺序,我可以:

  • Marshal struct to BSON
  • 哈希结果byte[]
  • 将hash放在struct
  • 将结构保存到mongo

哪个不那么讨厌(虽然它仍然需要两次转换为BSON)。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

回答您的实际问题,是的,您可以信任mgo/bson始终按照在代码中观察到的顺序封送结构字段。虽然尚未记录(issue),但这是非常有意的行为,甚至mgo本身也依赖于它。

现在,回应您的预期用法:不要这样做。事实字段处于保证顺序并不意味着二进制格式整体上是稳定的。即使是现在,已知的方法可以在不破坏现有客户端的情况下更改输出,但这会破坏其输出的哈希值。

以下是一些建议阅读,以便更好地了解您要解决的问题的来龙去脉(我是作者):

这正是解决了以任意字段和键以稳定的方式封送任意或映射的问题,以便从签名中获取稳定的散列。参考实现在Go中。

答案 1 :(得分:0)

BSON保持秩序。我会在一些简单的包装函数中做所有秘密:

type StructWrap struct{
    Value bson.Raw
    Hash []byte
}

func save2mgo(in interface{}){
    str := StructWrap{}
    orig,_err := bson.Marshal(in)
    str.Value = bson.Raw{0, orig}
    str.Hash = <do hash based on orig bytes>
    //to save str to mgo. because Value already in bson.Raw, it will not do marshal again.
}

func unmarshal(inType interface{}){
    //read from mgo
    //check str.Hash here 
    str.Value.Unmarshal(inType)
}

希望可以帮到你。