184.5. Jackson ObjectMapper
184.5.1. オブジェクトマッピングとは
Jackson は、com.fasterxml.jackson.databind.ObjectMapper
クラスを使用して、Java オブジェクトをシリアライズするメカニズムを提供します。たとえば、次のように ObjectMapper
を使用して MyClass
Java オブジェクトをシリアライズできます。
ObjectMapper objectMapper = new ObjectMapper(); MyClass myobject = new MyClass("foo", "bar"); objectMapper.writeValue(new File("myobject.json"), myobject);
オブジェクト myobject
は JSON 形式にシリアル化され、ファイル myobject.json
に書き込まれます (Jackson は XML および YAML 形式への変換もサポートしています)。
ファイル myobject.json
の JSON コンテンツをデシリアライズするには、次のように ObjectMapper
を呼び出します。
ObjectMapper objectMapper = new ObjectMapper(); MyClass myobject = objectMapper.readValue(new File("myobject.json"), MyClass.class);
受信者は事前にクラスの型を知っている必要があり、型 MyClass.class
を readValue ()
の 2 番目の引数として指定する必要があることに注意してください。
184.5.2. ポリモーフィックオブジェクトマッピングとは
場合によっては、シリアル化されたオブジェクトの受信者がオブジェクトの型を事前に知ることができないことがあります。たとえば、これは多相オブジェクト配列の場合に当てはまります。抽象型 Shape
とそのサブタイプ Triangle
、Square
(など) について考えてみましょう。
package com.example; ... public abstract class Shape { } public class Triangle extends Shape { ... } public class Square extends Shape { ... } public class ListOfShape { public List<Shape> shapes; ... }
次のように、形状の配列リスト (ListOfShape
) をインスタンス化してシリアル化できます。
ObjectMapper objectMapper = new ObjectMapper(); ListOfShape shapeList = new ListOfShape(); shapeList.shapes = new ArrayList<Shape>(); shapeList.shapes.add(new Triangle()); shapeList.shapes.add(new Square()); String serialized = objectMapper.writeValueAsString(shapeList);
しかし、今は受信側に問題があります。この型を readValue()
の 2 番目の引数として指定することで、受信側に ListOfShape
オブジェクトを期待するように指示できます。
MyClass myobject = objectMapper.readValue(serialized, ListOfShape.class); ObjectMapper objectMapper = new ObjectMapper();
ただし、リストの最初の要素が Triangle
で 2 番目の要素が Square
であることを受信者が知る方法はありません。この問題を回避するには、次のセクションで説明するように、ポリモーフィックオブジェクトマッピング を有効にする必要があります。
184.5.3. ポリモーフィックオブジェクトマッピングを有効にする方法
ポリモーフィックオブジェクトマッピングは、配列内のオブジェクトの型を識別する追加のメタデータをシリアル化された配列に提供することによって、抽象クラスの配列をシリアル化および逆シリアル化できるようにするメカニズムです。
ポリモーフィックオブジェクトマッピングには固有のセキュリティーリスクがあります。このメカニズムでは、インスタンス化するクラスを 送信者 が選択できるため、送信者による攻撃の基礎となる可能性があります。Red Hat の FasterXML Jackson ライブラリーのディストリビューションは、この脅威に対する追加レベルの保護を提供するホワイトリストメカニズムを特徴としています。この追加の保護レイヤーを取得するには、Red Hat の jackson-databind ライブラリーのディストリビューション (Fuse バージョン 7.7 以降で提供) を使用していることを確認する必要があります。詳細は、「ポリモーフィックデシリアライゼーションによるセキュリティーリスク」 を参照してください。
受信者が配列内のオブジェクトを逆シリアル化できるようにするには、シリアル化されたデータに型メタデータを提供する必要があります。デフォルトでは、Jackson はシリアル化されたオブジェクトのタイプメタデータをエンコードしないため、この機能を有効にするには追加のコードを記述する必要があります。
ポリモーフィックオブジェクトマッピングを有効にするには、次の手順を実行します (例として ListOfShape
を使用)。
リストの要素となるクラス (
Shape
のサブクラス) ごとに、次のように@JsonTypeInfo
でクラスにアノテーションを付けます。@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY) public class Triangle extends Shape { ... }
Triangle
クラスを JSON 形式にシリアル化すると、次の形式になります。{"@class":"com.example.Triangle", "property1":"value1", "property2":"value2", ...}
Triangle
、Square
、およびその他の形状クラスを逆シリアル化ホワイトリストに追加して、これらのクラスの逆シリアル化を許可するようにレシーバーを設定する必要があります。ホワイトリストを設定するには、jackson.deserialization.whitelist.packages
システムプロパティーを、クラスおよびパッケージのコンマ区切りリストに設定します。たとえば、Triangle
クラスとSquare
クラスのデシリアライズを許可するには、システムプロパティーを以下のように設定します。-Djackson.deserialization.whitelist.packages=com.example.Triangle,com.example.Square
または、システムプロパティーを設定して、
com.example
パッケージ全体を許可することもできます。-Djackson.deserialization.whitelist.packages=com.example
注記このホワイトリストメカニズムは、Red Hat の jackson-databind ライブラリーのディストリビューションでのみ使用できます。標準の jackson-databind ライブラリーは代わりにブラックリストメカニズムを使用します。このメカニズムは、潜在的に危険な新しいガジェットクラスが発見されるたびに更新する必要があります。
184.5.4. ポリモーフィックデシリアライゼーションのデフォルトマッピング
特定の Java クラス com.example.MyClass
がホワイトリストに登録されていない場合でも、クラスのインスタンスをシリアライズすることは可能ですが、受信側では、インスタンスは汎用のデフォルトマッピングを使用してデシリアライズされます。
Jackson でポリモーフィックオブジェクトマッピングが有効になっている場合、オブジェクトをエンコードする別の方法がいくつかあります。
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY)
の場合:{"@class":"com.example.MyClass", "property1":"value1", "property2":"value2", ...}
この場合、インスタンスはプロパティーを持つ
Object
に逆シリアル化されます。@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.WRAPPER_ARRAY)
の場合:["com.example.MyClass", {"property1":"value1", "property2":"value2", ...}]
この場合、インスタンスは 2 つのフィールドを含む JSON 配列に逆シリアル化されます。
-
値が
com.example.MyClass
のString
-
2 つ (またはそれ以上) のプロパティーを持つ
Object
-
値が
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.WRAPPER_OBJECT)
の場合:{"com.example.MyClass":{"property1":"value1", "property2":"value2", ...}}
この場合、インスタンスは、1 つのフィールド
com.example.MyClass
と、2 つ (またはそれ以上) のプロパティーを持つObject
としての値を持つ JSON マップに逆シリアル化されます。
184.5.5. ポリモーフィックデシリアライゼーションによるセキュリティーリスク
FasterXML jackson-databind
ライブラリーを使用し、JSON コンテンツをデシリアライズして Java オブジェクトをインスタンス化するアプリケーションは、潜在的に リモートコード実行 攻撃に脆弱です。しかし、脆弱性は自動的に発生せず、適切な軽減策を講じれば回避することができます。
最低でも以下の前提条件をすべて満たさなければ攻撃を実行することはできません。
jackson-databind
の JSON コンテンツのデシリアライズに対し、ポリモーフィックな型の処理を有効にする必要があります。Jackson JSON でポリモーフィックな型の処理を有効にする方法は 2 つあります。-
@JsonTypeInfo
および@JsonSubTypes
アノテーションの組み合わせを使用します。 -
ObjectMapper.enableDefaultTyping()
メソッドを呼び出します。この方法はポリモーフィックな型をグローバルで有効にするため、危険です。
-
- Java クラスパスに 1 つ以上の ガジェットクラス があります。ガジェットクラスは、機密性の高い (潜在的に悪用可能な) 操作を、constructor または setter メソッド (デシリアライズ中に呼び出しできるメソッド) の実行による副次的な影響として定義します。
-
Java クラスパス内の 1 つ以上のガジェットクラスが、現在のバージョンの
jackson-databind
によってまだブラックリストに登録されていません。jackson-databind ライブラリーの標準ディストリビューションを使用している場合、Jackson JSON ライブラリーによって維持されるガジェットのブラックリストは、リモートコード実行の脆弱性に対する最後の防衛線です。 -
(jackson-databind ライブラリーの Red Hat ディストリビューションのみ) (
jackson.deserialization.whitelist.packages
システムプロパティーを設定することにより) レシーバーの逆シリアル化ホワイトリストにガジェットクラスの 1 つを明示的に追加しました。これを行う可能性は低いため、ホワイトリストメカニズムはデフォルトですべてのガジェットクラスに対して効果的な保護を提供します。