一覧SP-23-3 · DDoS・Bot・API保護:要求の分布と仕様

APIの把握とスキーマ・権限の検証

未登録API、入力形式の不備、対象への権限不足を、それぞれの検査で確認します。

説明

API保護では、対象のエンドポイントを把握し、入力形式と権限を評価します。スキーマに合うJSONであっても、その利用者が指定した対象を更新してよいとは限りません。

固定のAPI台帳と観測記録を照合し、JSON Schema 2020-12の実装で型・上限・余分な項目を検査します。最後に所有者条件を含めた更新を試します。

未登録API、入力形式の不備、対象への権限不足を、それぞれの検査で確認します。

1台帳と観測された経路を照合する

メソッドとパスの組をキーにします。

from sp23 import * from sp02 import show db=connect() show(db,"SELECT o.method,o.path,e.owner,e.schema_version FROM observed o LEFT JOIN台帳と観測された経路を照合する endpoint e USING(method,path) ORDER BY o.path,o.method")

POST /legacy/ordersは台帳にありません。既知エンドポイントだけの検査結果を、全APIの保護範囲と扱わないようにします。

2入力スキーマを開く

idとquantityが必須で、余分な項目を許さない形式です。

print(json.dumps(SCHEMA,indent=2)) Draft202012Validator.check_schema入力スキーマを開く(SCHEMA)

quantityは1以上5以下の整数です。check_schemaはスキーマ自体を確認し、実際の要求データの合否は次に調べます。

3正しい入力と型の違いを検査する

整数、数字文字列、真偽値を比較します。

print(errors正しい入力と型の違いを検査する({'id':7,'quantity':2})) print(errors({'id':7,'quantity':'2'})) print(errors({'id':7,'quantity':True}))

整数だけが空のエラー一覧です。数字の文字列やtrueを数量として黙って変換しません。JSON Schemaの整数判定では真偽値は整数に含まれません。

4上限と余分な項目を検査する

数量6と、許可していないowner項目を試します。

print(errors上限と余分な項目を検査する({'id':7,'quantity':6})) print(errors({'id':7,'quantity':2,'owner':'bob'}))

maximumとadditionalPropertiesのエラーです。アプリが更新してよい項目を契約として限定します。

5形式が正しい他人の対象を指定する

aliceがbobの注文8を指定した場合です。

payload={'id':8,'quantity':2} print(errors(payload)) cur=db.execute("UPDATE orders SET quantity=? WHERE id=? AND owner=?形式が正しい他人の対象を指定する",(payload['quantity'],payload['id'],'alice')) print(cur.rowcount)

スキーマは通りますが更新は0行です。入力形式の検査と、対象の所有者に基づく認可を組み合わせます。

6本人の対象だけを更新する

同じ数量2をaliceの注文7へ適用します。

payload={'id':7,'quantity':2} print(errors(payload)) print(db.execute("UPDATE orders SET quantity=? WHERE id=? AND owner=?",(payload['quantity'],payload['id'],'alice')).rowcount) show本人の対象だけを更新する(db,"SELECT * FROM orders ORDER BY id")

注文7だけ2になり、bobの注文8は1のままです。更新件数と原表を読み直して範囲を確かめます。

7検査対象外を台帳の課題として残す

未登録のメソッド・パスを抽出します。

show検査対象外を台帳の課題として残す(db,"SELECT o.method,o.path FROM observed o LEFT JOIN endpoint e USING(method,path) WHERE e.path IS NULL")

POST /legacy/ordersが残ります。既知APIの入力検査を強化しただけで、未登録経路の問題も解消したとは報告しません。

まとめ

メソッドとパスをAPI台帳へ照合します。

実スキーマ検証で型・範囲・項目を確認します。

スキーマと資源単位の認可を両方適用します。

操作履歴と解説を振り返れます。

Python 3.15 / 固定要求列・HMAC・JSON Schema 2020-12

1
from sp23 import * from sp02 import show db=connect() show(db,"SELECT o.method,o.path,e.owner,e.schema_version FROM observed o LEFT JOIN endpoint e USING(method,path) ORDER BY o.path,o.method")
method | path | owner | schema_version
POST | /legacy/orders | NULL | NULL
GET | /orders | team-a | 1
POST | /orders | team-a | 1
2
print(json.dumps(SCHEMA,indent=2)) Draft202012Validator.check_schema(SCHEMA)
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": [
    "id",
    "quantity"
  ],
  "properties": {
    "id": {
      "type": "integer",
      "minimum": 1
    },
    "quantity": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    }
  },
  "additionalProperties": false
}
3
print(errors({'id':7,'quantity':2})) print(errors({'id':7,'quantity':'2'})) print(errors({'id':7,'quantity':True}))
[]
[('type', 'quantity')]
[('type', 'quantity')]
4
print(errors({'id':7,'quantity':6})) print(errors({'id':7,'quantity':2,'owner':'bob'}))
[('maximum', 'quantity')]
[('additionalProperties', '')]
5
payload={'id':8,'quantity':2} print(errors(payload)) cur=db.execute("UPDATE orders SET quantity=? WHERE id=? AND owner=?",(payload['quantity'],payload['id'],'alice')) print(cur.rowcount)
[]
0
6
payload={'id':7,'quantity':2} print(errors(payload)) print(db.execute("UPDATE orders SET quantity=? WHERE id=? AND owner=?",(payload['quantity'],payload['id'],'alice')).rowcount) show(db,"SELECT * FROM orders ORDER BY id")
[]
1
id | owner | quantity
7 | alice | 2
8 | bob | 1
7
show(db,"SELECT o.method,o.path FROM observed o LEFT JOIN endpoint e USING(method,path) WHERE e.path IS NULL")
method | path
POST | /legacy/orders

演習完了