本記事は「Kong Advent Calendar 2025」の13日目のエントリとして、JSON Threat Protection Pluginについて解説する。
先日、AI関連の論文プラットフォーム「OpenReview」において、BOLA (Broken Object Level Authorization) に起因する深刻な脆弱性が報告された。
非公開Group IDの悪用により不正アクセスが可能だったこの事例は、APIセキュリティの重要性を改めて浮き彫りにした。
API保護には多層的な対策が必要となるが、今回はその基礎となる「入力データの構造検証」に焦点を当てる。
Kong GatewayのJSON Threat Protection Pluginを利用し、肥大化したペイロードや深いネストなど、システムに負荷を与える不正なJSONリクエストを検知・遮断する方法について解説する。
JSON Threat Protection Pluginとは
JSON Threat Protection Pluginは、設定されたポリシーと照らし合わせて、JSONリクエストの構造を検証するKong Gatewayのプラグインである。
以下の特徴がある。
- 違反ポリシーと合致した場合、ブロックするかログに残すだけにするかの2種類が選択できる
- 対象リクエストのメソッドはPOST、PUT、PATCHに限定される
- ポリシーで設定できる項目は以下
- JSONオブジェクトの深度
- 配列要素の最大数
- オブジェクトエントリの最大数
- オブジェクトキーの最大数
- 文字列の最大数
- ボディのサイズ
イメージ的にはJSONの以下のようなところをチェックしてガードする感じ。

このように、ペイロードの中身を検証するようなことは出来ないが、JSONの構造から攻撃を検知することが出来るようになっている。
具体的な設定値は以下となる。
| パラメータ | 型 | デフォルト値 | 説明 |
|---|---|---|---|
allow_duplicate_object_entry_name |
boolean | true |
JSONオブジェクト内でキーの重複を許可するかどうか |
enforcement_mode |
string | block |
セキュリティポリシーの適用モードを指定 ・ block: 違反したリクエストを遮断・ log_only: 遮断はせず、ログ出力のみ実施 |
error_message |
string | Bad Request |
問題検出時のクライアントへ返すエラーメッセージを指定 |
error_status_code |
integer | 400 |
問題検出時のクライアントへ返すHTTPステータスコードを指定(400~499の範囲)。 |
max_array_element_count |
integer | -1 |
配列に含まれる要素数の最大値を指定。(-1 は無制限) |
max_body_size |
integer | 8192 |
リクエストボディの最大サイズ(バイト数)を指定。(-1 は無制限) |
max_container_depth |
integer | -1 |
オブジェクトや配列のネスト(入れ子)の深さの最大値を指定。(-1 は無制限) |
max_object_entry_count |
integer | -1 |
1つのオブジェクトに含まれるエントリ(キーと値のペア)の最大数を指定。(-1 は無制限) |
max_object_entry_name_length |
integer | -1 |
オブジェクトのキー(エントリ名)の最大文字数を指定。(-1 は無制限) |
max_string_value_length |
integer | -1 |
文字列の値の最大文字数を指定。(-1 は無制限) |
検証
ここでは以下のデータをPOSTして、JSON Threat Protection Pluginが正しく動作するか確認する。
{
"account": "ipppppei",
"age": 18,
"favorite": ["sake", "beer", "whisky", "rum"],
"address": {
"street": "1-2-3",
"city": "Tokyo",
"country": {
"name": "Japan",
"code": "+81"
},
"postal": "1234567"
},
"extra_field": "1234567890"
}
Kong Gatewayでは以下の設定をdeckで適用している。
_format_version: "3.0"
services:
- host: httpbin.konghq.com
name: httpbin-service
path: /
port: 443
protocol: https
routes:
- name: httpbin-route
paths:
- /httpbin
plugins:
- config:
max_array_element_count: 3
max_container_depth: 2
max_object_entry_count: 5
max_object_entry_name_length: 10
max_string_value_length: 9
enabled: true
name: json-threat-protection
投げるJSONについては以下の点でポリシー違反が発生する。
-
max_array_element_count: favorite配列の要素数が4でポリシー違反 -
max_container_depth: address.countryオブジェクトが深さ3でポリシー違反 -
max_object_entry_count: addressオブジェクトのエントリ数が6でポリシー違反 -
max_object_entry_name_length: extra_fieldキーの文字数が11でポリシー違反 -
max_string_value_length: extra_fieldの値が10でポリシー違反
確認してみる。
まずJSONデータを環境変数に設定する。
export MY_JSON_DATA='{
"account": "ipppppei",
"age": 18,
"favorite": ["sake", "beer", "whisky", "rum"],
"address": {
"street": "1-2-3",
"city": "Tokyo",
"country": {
"name": "Japan",
"code": "+81"
},
"postal": "1234567"
},
"extra_field": "1234567890"
}'
リクエストを発行する。
curl -X POST http://localhost:8000/httpbin/post \
-H "Content-Type: application/json" \
-d "$MY_JSON_DATA" -i
するとHTTP/1.1 400 Bad Requestと共に以下のエラーメッセージが確認できる。
{
"message":"Bad Request",
"request_id":"592a9e699e44b713bbf88649e0d6c64a"
}
プラグインは正常に動作しており、ポリシー違反のリクエストが遮断されたことが分かる。
具体的にどのようなポリシー違反だったかはKongのエラーログを確認することで分かる。
2025/12/11 23:18:51 [warn] 2631#0: *109862 [kong] handler.lua:87 [json-threat-protection] JSON validate failed: at [$.favorite]: The maximum number of elements allowed in an array is exceeded., client: 172.18.0.1, server: kong, request: "POST /httpbin/post HTTP/1.1", host: "localhost:8000", request_id: "1e5a8223f2e072366417bf234edfc375"
エラーは1つだけでfavoriteがmax_array_element_countに違反していることが分かる。
他のポリシー違反についてはログ出力されていないため、1つ違反を検知するとその時点で処理を中断していると思われる。
またリクエストに応答するエラーメッセージに含まないのは攻撃者にヒントを与えないためであり、エラーの内容をクライアント側に伝えることは出来ない。
再度検証する。
favorite配列の要素数を3に減らして再度リクエストを発行すると、以下のエラーメッセージに変化した。
2025/12/11 23:21:33 [warn] 2632#0: *109865 [kong] handler.lua:87 [json-threat-protection] JSON validate failed: at [$.address.country]: The maximum allowed nested depth is exceeded., client: 172.18.0.1, server: kong, request: "POST /httpbin/post HTTP/1.1", host: "localhost:8000", request_id: "2ac5ba47c3935001b1a7700a7ff68872"
今度はaddress.countryがmax_container_depthに違反していることが分かる。
address.countryオブジェクトを削除して再度リクエストを発行すると、以下のエラーメッセージに変化した。
2025/12/11 23:26:09 [warn] 2633#0: *109873 [kong] handler.lua:87 [json-threat-protection] JSON validate failed: at [$.extra_field]: The maximum string length allowed in an object's entry name is exceeded., client: 172.18.0.1, server: kong, request: "POST /httpbin/post HTTP/1.1", host: "localhost:8000", request_id: "d5706f248f2405125bd948487f609948"
extra_fieldの値がmax_object_entry_name_lengthに違反していることが分かる。
extra_fieldキーをextrafieldに変更して再度リクエストを発行すると、以下のエラーメッセージに変化した。
2025/12/11 23:36:32 [warn] 2630#0: *110918 [kong] handler.lua:87 [json-threat-protection] JSON validate failed: at [$.extrafield]: The maximum length allowed for a string value is exceeded., client: 172.18.0.1, server: kong, request: "POST /httpbin/post HTTP/1.1", host: "localhost:8000", request_id: "f15bb6406ee3de422904484a91709e79"
今度はextrafieldの値がmax_string_value_lengthに違反していることが分かる。
最後にextrafieldキーと値を以下のように修正してリクエストを発行する。
export MY_JSON_DATA='{
"account": "ipppppei",
"age": 18,
"favorite": ["sake", "beer", "whisky"],
"address": {
"street": "1-2-3",
"city": "Tokyo",
"postal": "1234567"
},
"extrafield": "123456789"
}'
するとHTTP/1.1 200 OKが返ってリクエストが正常に通る。
以上より、JSON Threat Protection Pluginが正しく動作していることが確認できた。
まとめ
今回はKong GatewayのJSON Threat Protection Pluginを利用して、JSONリクエストの構造を検証し、想定外のリクエストを抑止する方法について確認した。
APIセキュリティの基礎として、JSONリクエストの構造検証は潜在的な攻撃からAPIを保護する有効な手段となると思う。
特定の攻撃方法に対する防御策ではないが、漠然とAPIセキュリティを気にしている人はJSON Threat Protection Pluginの導入を検討するとよいと思う。