JSONオブジェクトを暗号化する方法は?
-
10-10-2019 - |
質問
次の質問は、最初に見えるよりも複雑です。
任意のJSONオブジェクトがあると仮定します。これは、他のネストされたJSONオブジェクトを含む量のデータを含む可能性があります。私が欲しいのは、実際のJSONフォーマット自体に関係なく、JSONデータの暗号化ハッシュ/ダイジェストです(例:JSONトークンの間隔の違いを無視します)。
JSONは、さまざまなプラットフォームでさまざまな(DE)シリアライザーによって生成/読み取られるため、最後の部分は要件です。私は、Daserialization中にデータを読むときにフォーマットを完全に削除するJavaの少なくとも1つのJSONライブラリを知っています。そのため、ハッシュが壊れます。
上記の任意のデータ条項も物事を複雑にします。これは、既知のフィールドを特定の順序で採取し、ハスする前にそれらを連結することを妨げているためです(Javaの非暗号化ハッシュコード()メソッドがどのように機能するかを大まかに考えてください)。
最後に、JSON文字列全体をバイトの塊としてハッシュすることも望ましくありません。これは、ハッシュを計算するときに無視する必要があるJSONにフィールドがあるためです。
この問題に良い解決策があるかどうかはわかりませんが、アプローチや考えを歓迎します=)
解決
問題は、柔軟性が許可されているデータ形式のハッシュを計算する場合、一般的なものです。これを解決するには、する必要があります 正規化します 表現。
たとえば、Twitterやその他のサービスが認証に使用するOAUTH1.0Aプロトコルには、リクエストメッセージの安全なハッシュが必要です。ハッシュを計算するには、OAUTH1.0Aは、最初にフィールドをアルファベット化し、ニューラインで分離し、フィールド名(よく知られている)を削除し、空の値に空白行を使用する必要があると言います。署名またはハッシュは、その標準化の結果で計算されます。
XML DSIGは同じように動作します - 署名する前にXMLを正規化する必要があります。があります これをカバーする提案されたW3標準, 、それは署名のためのこのような基本的な要件だからです。一部の人々はそれをC14Nと呼んでいます。
JSONの標準化基準を知りません。調査する価値があります。
ない場合は、特定のアプリケーション使用に関する慣習を確実に確立できます。合理的なスタートは次のとおりです。
- 名前でプロパティを辞書的に並べ替えます
- すべての名前で使用される二重引用符
- すべての文字列値で使用される二重引用符
- 名前とコロンの間、およびコロンと値の間にスペース、または1つのスペースがない
- 値と次のコンマの間にスペースはありません
- 他のすべての空白が単一のスペースまたは何もないかどうかに崩壊しました - 1つを選択します
- 署名したくないプロパティを除外します(1つの例は、署名自体を保持するプロパティです)
- 選択したアルゴリズムで結果に署名します
また、JSONオブジェクトでその署名を渡す方法を考えたい場合があります。おそらく、「Nichols-HMAC」などの有名なプロパティ名を確立し、HashのBase64エンコードバージョンを取得します。このプロパティは、ハッシュアルゴリズムによって明示的に除外する必要があります。次に、JSONの受信者はハッシュを確認できます。
標準化された表現は、アプリケーションで渡す表現である必要はありません。任意のJSONオブジェクトを考えると、簡単に作成する必要があります。
他のヒント
独自のJSON正規化/標準化を発明する代わりに、使用することをお勧めします ベンコード. 。意味的には、JSON(数字、文字列、リスト、およびdictの構成)と同じですが、暗号化に必要な明確なエンコードの特性を使用します。
ベンコードはトレントファイル形式として使用され、すべてのBitTorrentクライアントには実装が含まれています。
これは、S/MIME署名とXMLシグネチャの問題を引き起こすのと同じ問題です。つまり、署名するデータの複数の同等の表現があります。
たとえば、JSON:
{ "Name1": "Value1", "Name2": "Value2" }
vs。
{
"Name1": "Value\u0031",
"Name2": "Value\u0032"
}
または、アプリケーションに応じて、これは同等の場合もあります。
{
"Name1": "Value\u0031",
"Name2": "Value\u0032",
"Optional": null
}
標準化はその問題を解決する可能性がありますが、それはあなたがまったく必要としない問題です。
仕様を制御できる場合の簡単なソリューションは、オブジェクトを何らかの容器にラップして、「同等の」とは異なる表現に変換されないように保護することです。
つまり、「論理」オブジェクトに署名するのではなく、代わりに特定のシリアル化された表現に署名することにより、問題を回避します。
たとえば、JSONオブジェクト - > UTF -8テキスト - >バイト。バイトに署名します バイトとして, 、次にそれらを送信します バイトとして 例:base64エンコーディング。バイトに署名しているため、Whitespaceのような違いは署名の一部です。
これをやろうとする代わりに:
{
"JSONContent": { "Name1": "Value1", "Name2": "Value2" },
"Signature": "asdflkajsdrliuejadceaageaetge="
}
これを行うだけです:
{
"Base64JSONContent": "eyAgIk5hbWUxIjogIlZhbHVlMSIsICJOYW1lMiI6ICJWYWx1ZTIiIH0s",
"Signature": "asdflkajsdrliuejadceaageaetge="
}
つまり、jsonに署名しないでください、サイン エンコードされたバイト JSON。
はい、それは署名がもはや透明ではないことを意味します。
json-ld 普通はできます。
コンテキストを定義する必要があります。
RFC 7638:JSON Webキー(JWK)Thumbprintには、標準化の種類が含まれています。 RFC7638は限られたメンバーセットを期待していますが、メンバーに同じ計算を適用することができます。
特定の順序ですべてのフィールドを実行します(たとえば、アルファベット順に)。任意のデータが違いを生むのはなぜですか?プロパティ(ALA反射)を繰り返すだけです。
あるいは、生のJSON文字列を明確に定義された標準形式に変換することを検討します(すべての超流formattingを削除します) - それをハッシュします。
JSONエンコードのペイロードをハッシュすることで簡単な問題に遭遇しました。私たちの場合、次の方法論を使用します。
- データをJSONオブジェクトに変換します。
- base64でJSONペイロードをエンコードします
- Message Digest(HMAC)生成されたBase64ペイロード。
- Base64ペイロードを送信します。
このソリューションを使用することの利点:
- Base64は、特定のペイロードに対して同じ出力を生成します。
- 結果の署名はBase64でエンコードされたペイロードから直接導出され、Base64-Payloadはエンドポイント間で交換されるため、署名とペイロードが維持されることを確認します。
- このソリューションは、特殊文字のエンコードの違いにより発生する問題を解決します。
短所
- ペイロードのエンコード/デコードはオーバーヘッドを追加する場合があります
- Base64エンコードデータは、通常、元のペイロードよりも30+%+%大きくなっています。