45

Rubyで変数の署名文字列を作成する必要があります。変数は、数値、文字列、ハッシュ、または配列にすることができます。ハッシュ値と配列要素もこれらのタイプのいずれかになります。

この文字列は、データベース(この場合はMongo)の値を比較するために使用されます。

私の最初の考えは、次のように、JSONでエンコードされた値のMD5ハッシュを作成することでした:(本体は上記で参照されている変数です)

def createsig(body)    
  Digest::MD5.hexdigest(JSON.generate(body))
end

これはほぼ機能しますが、JSON.generateは毎回同じ順序でハッシュのキーをエンコードしないため、createsig({:a=>'a',:b=>'b'})常に等しいとは限りませんcreatesig({:b=>'b',:a=>'a'})

このニーズに合う署名文字列を作成するための最良の方法は何ですか?

注:私たちの間で重視されている詳細についてはJSON.generate()、数字や文字列は使用できないことを知っています。このような場合は、MD5.hexdigest()直接電話します。

4

6 に答える 6

33

私は以下をかなり迅速にコーディングしていて、ここで実際にテストする時間がありませんが、それでうまくいくはずです。問題があればお知らせください。調査させていただきます。

これにより、配列とハッシュが適切にフラット化およびソートされ、衝突が発生するためには、かなり奇妙に見える文字列が必要になります。

def createsig(body)
  Digest::MD5.hexdigest( sigflat body )
end

def sigflat(body)
  if body.class == Hash
    arr = []
    body.each do |key, value|
      arr << "#{sigflat key}=>#{sigflat value}"
    end
    body = arr
  end
  if body.class == Array
    str = ''
    body.map! do |value|
      sigflat value
    end.sort!.each do |value|
      str << value
    end
  end
  if body.class != String
    body = body.to_s << body.class.to_s
  end
  body
end

> sigflat({:a => {:b => 'b', :c => 'c'}, :d => 'd'}) == sigflat({:d => 'd', :a => {:c => 'c', :b => 'b'}})
=> true
于 2011-06-24T02:02:48.267 に答える
15

の文字列表現しか取得できずbody、Ruby 1.8ハッシュが一度に異なる順序で返されることがない場合は、その文字列表現を確実にハッシュできます。いくつかのモンキーパッチで手を汚しましょう:

require 'digest/md5'

class Object
  def md5key
    to_s
  end
end

class Array
  def md5key
    map(&:md5key).join
  end
end

class Hash
  def md5key
    sort.map(&:md5key).join
  end
end

これで、(質問で言及されているタイプの)オブジェクトはmd5key、チェックサムの作成に使用する信頼できるキーを返すことで応答します。

def createsig(o)
  Digest::MD5.hexdigest(o.md5key)
end

例:

body = [
  {
    'bar' => [
      345,
      "baz",
    ],
    'qux' => 7,
  },
  "foo",
  123,
]
p body.md5key        # => "bar345bazqux7foo123"
p createsig(body)    # => "3a92036374de88118faf19483fe2572e"

注:このハッシュ表現は構造をエンコードせず、値の連結のみをエンコードします。したがって、["a"、 "b"、"c"]は["abc"]と同じようにハッシュされます。

于 2011-06-24T21:53:31.727 に答える
1

これが私の解決策です。私はデータ構造を歩き、単一の文字列に結合される部分のリストを作成します。表示されるクラスタイプがハッシュに影響を与えることを確認するために、途中で基本的なタイプ情報をエンコードする単一のUnicode文字を挿入します。(たとえば、["1"、 "2"、 "3"]。objsum!= [1,2,3] .objsumが必要です)

私はこれをObjectの改良として行いました。これは、モンキーパッチに簡単に移植できます。これを使用するには、ファイルが必要で、「usingObjSum」を実行するだけです。

module ObjSum
  refine Object do
    def objsum
      parts = []
      queue = [self]

      while queue.size > 0
        item = queue.shift

        if item.kind_of?(Hash)
          parts << "\\000"
          item.keys.sort.each do |k| 
            queue << k
            queue << item[k]
          end
        elsif item.kind_of?(Set)
          parts << "\\001"
          item.to_a.sort.each { |i| queue << i }
        elsif item.kind_of?(Enumerable)
          parts << "\\002"
          item.each { |i| queue << i }
        elsif item.kind_of?(Fixnum)
          parts << "\\003"
          parts << item.to_s
        elsif item.kind_of?(Float)
          parts << "\\004"
          parts << item.to_s
        else
          parts << item.to_s
        end
      end

      Digest::MD5.hexdigest(parts.join)
    end
  end
end
于 2013-11-22T07:18:02.137 に答える
1

ちょうど私の2セント:

module Ext
  module Hash
    module InstanceMethods
      # Return a string suitable for generating content signature.
      # Signature image does not depend on order of keys.
      #
      #   {:a => 1, :b => 2}.signature_image == {:b => 2, :a => 1}.signature_image                  # => true
      #   {{:a => 1, :b => 2} => 3}.signature_image == {{:b => 2, :a => 1} => 3}.signature_image    # => true
      #   etc.
      #
      # NOTE: Signature images of identical content generated under different versions of Ruby are NOT GUARANTEED to be identical.
      def signature_image
        # Store normalized key-value pairs here.
        ar = []

        each do |k, v|
          ar << [
            k.is_a?(::Hash) ? k.signature_image : [k.class.to_s, k.inspect].join(":"),
            v.is_a?(::Hash) ? v.signature_image : [v.class.to_s, v.inspect].join(":"),
          ]
        end

        ar.sort.inspect
      end
    end
  end
end

class Hash    #:nodoc:
  include Ext::Hash::InstanceMethods
end
于 2013-12-13T18:09:06.623 に答える
1

最近では、JSONを正規化するための正式に定義されたメソッドがあります。これはまさにこの理由によるものです:https ://datatracker.ietf.org/doc/html/draft-rundgren-json-canonicalization-scheme-16

ここにrubyの実装があります:https ://github.com/dryruby/json-canonicalization

于 2021-06-16T12:11:57.530 に答える
-1

必要に応じて、ary.inspectまたはary.to_yamlに電話することもできます。

于 2011-06-24T03:06:06.610 に答える