61

次の質問は、最初に思われるよりも複雑です。

任意のJSONオブジェクトがあり、他のネストされたJSONオブジェクトを含む任意の量のデータを含む可能性があると仮定します。私が欲しいのは、実際のJSONフォーマット自体に関係なく、JSONデータの暗号化ハッシュ/ダイジェストです(たとえば、JSONトークン間の改行と間隔の違いを無視します)。

JSONは、さまざまなプラットフォーム上のさまざまな(デ)シリアライザーによって生成/読み取られるため、最後の部分は要件です。逆シリアル化中にデータを読み取るときにフォーマットを完全に削除するJava用のJSONライブラリを少なくとも1つ知っています。そのため、ハッシュが壊れます。

上記の任意のデータ句は、既知のフィールドを特定の順序で取得し、それらを連結する前に連結することを妨げるため、事態を複雑にします(Javaの非暗号化hashCode()メソッドがどのように機能するかを大まかに考えてください)。

最後に、ハッシュを計算するときに無視する必要のあるフィールドがJSONにあるため、(逆シリアル化の前に)JSON文字列全体をバイトのチャンクとしてハッシュすることも望ましくありません。

この問題に良い解決策があるかどうかはわかりませんが、アプローチや考えを歓迎します=)

4

7 に答える 7

54

この問題は、柔軟性が許容される任意のデータ形式のハッシュを計算する場合によくある問題です。これを解決するには、表現を正規化する必要があります。

たとえば、Twitterやその他のサービスで認証に使用されるOAuth1.0aプロトコルには、リクエストメッセージの安全なハッシュが必要です。ハッシュを計算するには、OAuth1.0aは、最初にフィールドをアルファベット順に並べ、改行で区切り、フィールド名(よく知られている)を削除し、空の値に空白行を使用する必要があると言います。署名またはハッシュは、その正規化の結果に基づいて計算されます。

XML DSIGは同じように機能します。つまり、署名する前にXMLを正規化する必要があります。これは署名の基本的な要件であるため、これをカバーするW3標準が提案されています。それをc14nと呼ぶ人もいます。

jsonの正規化標準を知りません。調査する価値があります。

存在しない場合は、特定のアプリケーションの使用法に関する規則を確実に確立できます。妥当な開始点は次のとおりです。

  • プロパティを名前で辞書式順序で並べ替えます
  • すべての名前で使用される二重引用符
  • すべての文字列値で使用される二重引用符
  • 名前とコロンの間、およびコロンと値の間にスペースなし、または1つのスペース
  • 値とそれに続くコンマの間にスペースはありません
  • 他のすべての空白は、単一のスペースまたは何もないスペースに折りたたまれています-1つ選択してください
  • 署名したくないプロパティを除外します(1つの例は、署名自体を保持するプロパティです)
  • 選択したアルゴリズムで結果に署名します

また、JSONオブジェクトでその署名を渡す方法についても検討する必要があります。おそらく、base64でエンコードされたバージョンのハッシュを取得する「nichols-hmac」などのよく知られたプロパティ名を確立します。このプロパティは、ハッシュアルゴリズムによって明示的に除外する必要があります。そうすれば、JSONの受信者なら誰でもハッシュをチェックできます。

正規化された表現は、アプリケーションで渡す表現である必要はありません。任意のJSONオブジェクトを指定して簡単に作成する必要があるだけです。

于 2011-01-12T15:38:25.597 に答える
9

独自のJSON正規化/正規化を考案する代わりに、bencodeを使用することをお勧めします。意味的には、JSON(数値、文字列、リスト、およびdictの構成)と同じですが、暗号化ハッシュに必要な明確なエンコーディングの特性を備えています。

bencodeはトレントファイル形式として使用され、すべてのビットトレントクライアントには実装が含まれています。

于 2011-01-12T15:54:49.923 に答える
8

これは、S/MIME署名とXML署名で問題が発生するのと同じ問題です。つまり、署名するデータには同等の表現が複数あります。

たとえば、JSONの場合:

{  "Name1": "Value1", "Name2": "Value2" }

対。

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032"
}

または、アプリケーションによっては、これは同等の場合もあります。

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032",
    "Optional": null
}

正規化によってその問題を解決することはできますが、それはまったく必要のない問題です。

仕様を制御できる場合の簡単な解決策は、オブジェクトをある種のコンテナーでラップして、オブジェクトが「同等」であるが異なる表現に変換されないようにすることです。

つまり、「論理」オブジェクトに署名するのではなく、代わりにその特定のシリアル化された表現に署名することで、問題を回避します。

たとえば、JSONオブジェクト->UTF-8テキスト->バイト。バイトをバイトとして署名してから、たとえばbase64エンコーディングによってバイトとして送信します。バイトに署名しているので、空白のような違いは署名されたものの一部です。

これを試みる代わりに:

{  
   "JSONContent": {  "Name1": "Value1", "Name2": "Value2" },
   "Signature": "asdflkajsdrliuejadceaageaetge="
}

これを行うだけです:

{
   "Base64JSONContent": "eyAgIk5hbWUxIjogIlZhbHVlMSIsICJOYW1lMiI6ICJWYWx1ZTIiIH0s",
   "Signature": "asdflkajsdrliuejadceaageaetge="

}

つまり、JSONに署名するのではなく、エンコードされたJSONのバイトに署名します。

はい、それは署名がもはや透明ではないことを意味します。

于 2016-12-06T14:17:16.243 に答える
3

JSON-LDは正規化を行うことができます。

コンテキストを定義する必要があります。

于 2015-01-31T08:28:16.787 に答える
2

RFC 7638:JSON Web Key(JWK)拇印には、一種の正規化が含まれています。RFC7638は限られたメンバーのセットを想定していますが、どのメンバーにも同じ計算を適用できます。

https://www.rfc-editor.org/rfc/rfc7638#section-3

于 2018-12-22T02:24:18.890 に答える
0

すべてのフィールドを指定された順序で実行します(たとえば、アルファベット順)。なぜ任意のデータが違いを生むのですか?プロパティを反復処理するだけです(alaリフレクション)。

あるいは、生のjson文字列を明確に定義された標準形に変換して(余分なフォーマットをすべて削除して)、それをハッシュすることを検討します。

于 2011-01-12T15:37:05.700 に答える
0

JSONでエンコードされたペイロードのハッシュに関する単純な問題が発生しました。この場合、次の方法を使用します。

  1. データをJSONオブジェクトに変換します。
  2. JSONペイロードをbase64でエンコードする
  3. 生成されたbase64ペイロードのメッセージダイジェスト(HMAC)。
  4. base64ペイロードを送信します。

このソリューションを使用する利点:

  1. Base64は、特定のペイロードに対して同じ出力を生成します。
  2. 結果の署名はbase64でエンコードされたペイロードから直接派生し、base64-payloadはエンドポイント間で交換されるため、署名とペイロードが確実に維持されます。
  3. このソリューションは、特殊文字のエンコードの違いによって発生する問題を解決します。

短所

  1. ペイロードのエンコード/デコードはオーバーヘッドを追加する可能性があります
  2. Base64でエンコードされたデータは、通常、元のペイロードより30%以上大きくなります。
于 2018-04-05T02:08:27.890 に答える