1

I'm searching for a way to generate a SHA-512 hash from a json string in Ruby, independent from the positions of the elements in it, and independent from nestings, arrays, nested arrays and so on. I just want to hash the raw data along with its keys.

I tried some approaches with converting the JSON into a ruby hash, deep sort them by their keys, append everything into one, long string and hash it. But I bet that my solution isn't the most efficient one, and that there must be a better way to do this.

EDIT

So far, I convert JSON into a Ruby hash. Then I try to use this function to get a canonical representation:

  def self.canonical_string_from_hash value, key=nil
    str = ""
    if value.is_a? Hash
      value.keys.sort.each do |k|
        str += canonical_string_from_hash(value[k], k)
      end
    elsif value.is_a? Array
      str += key.to_s
      value.each do |v|
        str += canonical_string_from_hash(v)
      end
    else
      str += key ? "#{key}#{value}" : value.to_s
    end
    return str
  end

But I'm not sure, if this is a good and efficient way to do this.

For example, this hash

hash = {
  id: 3,
  zoo: "test",
  global: [
    {ukulele: "ringding", blub: 3},
    {blub: nil, ukulele: "rangdang", guitar: "stringstring"}
  ],
  foo: {
    ids: [3,4,5],
    bar: "asdf"
  }
}

gets converted to this string:

barasdfids345globalblub3ukuleleringdingblubguitarstringstringukulelerangdangid3zootest
4

1 回答 1

1

但我不确定这是否是一种很好且有效的方法。

取决于你想要做什么。您的规范/等效结构需要代表对您比较重要的内容。如果您考虑具有不同结构但相同字符串值等效的两个项目,则删除诸如对象结构之类的细节是有意义的。

根据您的评论,您正在尝试签署从一个系统传输到第二个系统的请求。换句话说,您需要安全性,而不是出于某种其他目的的相似性度量或数字指纹。因此,等效请求是在影响您要保护的处理的所有方面都相同的请求。锁定在两个系统之间传输的原始数据字节更简单,而且很可能更安全。

在这种情况下,您的整个方法需要重新考虑。其原因可能最好在 security.stackoverflow.com 上进行讨论

但是,简而言之:

  • 使用 HMAC 例程 (HMAC-SHA512),它专为您的目的而设计。这不是使用盐,而是使用秘密,这本质上是相同的(实际上,您需要在实现中对盐保密,这对于称为盐的东西来说是不寻常的),但已与 SHA 结合在一起一种使其能够抵御可能针对简单连接后跟 SHA 的几种攻击形式的方法。其中最糟糕的是,可以扩展数据并使其在处理时生成相同的 SHA,而无需知道 salt。换句话说,攻击者可以获取一个已知的有效请求并使用它来伪造其他可以通过您的安全检查的请求。您提出的解决方案在我看来很容易受到这种形式的攻击。

  • 解包请求并分析详细信息以获取请求的“规范”视图是不必要的,而且还会降低解决方案的安全性。这样做的唯一原因是,由于某种原因,一旦请求被序列化为 JSON,您将无法处理该请求,并且被迫仅在两个系统的一端或另一端处理反序列化的请求。如果这纯粹是知识或方便的事情,那么请解决该问题,而不是尝试使用 SHA-512 推出自己的安全协议。

  • 您应该根据完全序列化的 JSON 字符串对请求进行签名并检查签名。如果您需要从“中间人”攻击中反序列化数据,那么您可能已经通过解析器受到一些攻击。在对可疑请求进行任何数据处理之前,您应该努力拒绝这些请求。

TL;DR - 虽然不是您问题的直接答案,但您的正确解决方案是根本不编写此代码。相反,您需要将安全签名代码放在需要相互信任的两个服务的细节附近。

于 2013-11-14T14:21:14.120 回答