はじめに
API1:Broken Object Level Authorization
攻撃者/攻撃経路 | セキュリティの脆弱性 | 影響 |
---|---|---|
API固有 : 悪用容易性 3 | 発生頻度 3 : 検出容易性 2 | 技術的 3 : ビジネス固有 |
リクエストに識別子が含まれている場合、攻撃者はその識別子を変更することでエンドポイントを悪用できる可能性があります。例えば: /index.php?userID=1 攻撃者はこれを /index.php?userID=2 に変更し、本来閲覧できないデータを取得するかもしれません。この脆弱性が一般的なのは、APIベースのアプリがオブジェクト識別子に依存する一方で、利用者の権限確認がおろそかになりがちなためです。 | これはAPIエンドポイントで最も一般的な脆弱性です。現代のアプリは複数の連携ポイントから構成されるため、認証が非常に複雑になります。たとえ優れたセキュリティ設計と共通の認証フレームワークが整っていても、機能開発やリファクタリングの際に実装が漏れる可能性があります。通常、アクセス制御の自動化は困難なため、この脆弱性はさらに広がる恐れがあります。 | 非公開とされるべきデータが、権限のない利用者に漏洩する可能性があります。例えば、/index.php?id=1 が攻撃者が閲覧できない他の利用者のデータを表示する場合があります。また、POSTやPUTリクエストで適切なアクセス制御がなされたオブジェクトに対して攻撃者が操作を行うと、場合によっては攻撃者が他の利用者のメールアドレスを変更し、パスワードリセットにつながるなど、アカウントの完全乗っ取りにまで発展する恐れがあります。 |
Broken Object Level Authorisation (BOLA)は、すべてオブジェクトから始まる話です。オブジェクトとは、オブジェクト指向プログラミングの考え方における基本的な要素であり、プログラム設計の際に最初に検討する対象です。また、コードの単位としても扱われます。これはアカウント、請求書、クレジットノートなどあらゆるものが該当し、通常は個別に識別するためのIDが付与されています。しかし、そのオブジェクトにアクセスする許可があるかどうか、常に確認する必要があります。一見すると単純に思えますが、実際は複雑で、この点については後述の「テスト」セクションで詳しく説明します。
サーバーが、現在ログイン中の利用者やログアウト状態の利用者に、本来許可されていないオブジェクトの読み取り、更新、削除の権限があるかどうかを適切に確認しない場合に、このBroken Objectの問題が発生します。
オブジェクトに関するBroken Object Level Authorizationには2種類があり、利用者IDがサーバーに渡される場合とオブジェクトIDが渡される場合に分かれます。ここでは両方について説明します。
利用者の全リソースを取得する際など、利用者IDがサーバーに渡されるケースがあります。例えば:
<https://google.com/get_users_search_history?userID=1234>
もし利用者IDを他の利用者のものに置き換えても、本来は他の利用者の検索履歴は取得できないはずですが、Broken Object Level Authorizationの問題が起こると、他の利用者の検索履歴が閲覧できてしまいます。
この問題は、開発者にとっては解決が容易です。現在ログイン中の利用者が、そのオブジェクトにアクセスできるかどうかを確認すればよいのです。この例では、GETパラメータの利用者IDとオブジェクトの所有者の利用者IDが一致しているかを確認する必要があります。
擬似コード:
if($_GET['userID'] === object.ownerID){
ShowData()
} else {
echo "このデータの閲覧は許可されていません"
wait(5s)
Redirect(Homepage)
}
これが例外処理の最も安全な方法です。以下のコードは安全ではないので使用しないでください:
if(!$_GET['userID'] === object.ownerID) {
echo "このデータの閲覧は許可されていません"
wait(5s)
Redirect(Homepage)
}
ShowData()
リダイレクトによりデータは表示されませんが、戻るボタンを押すとデータが表示されてしまう可能性があります。
この脆弱性は、サーバーがオブジェクトに対する利用権限を適切に確認しないままオブジェクトIDが渡される場合にも発生します。例えば、あるリソースだけを守り、他は守らなくても良いと判断した際に、守るべきオブジェクトの防御設定を忘れるケースが考えられます。
どの種類の場合でも、共通する点がいくつか存在します。
これらの問題は、特に2つの状況で発生しやすいですが、もちろん、開発者が認証設定を忘れた場合にはいつでも発生し得ます。ここでは2つの例に焦点を当てます:
POST updateProduct.php?productID?id=1
if($_GET['productID'].owner === object.ownerID){
UpdateData()
} else {
echo "このデータの閲覧は許可されていません"
wait(5s)
Redirect(Homepage)
}
POST /import.php?
StartUpdateData()
この擬似コード例では、説明した脆弱性が実際に動作している様子が確認できます。
TimerForProducts(){
wait(24H)
UpdatePrices($_GET[UsersProducts[])
}
UpdatePrices(products[]) {
for each product in products{
getPrice()
}
}
GET /updatePrices?UsersProducts=1,2,3,4
攻撃者は、任意のproductIDを渡すことでこのバックグラウンド呼び出しを簡単に悪用できます。
GET /updatePrices?UsersProducts=1,2,3,4,5,6,7,8,9,...
検出
この脆弱性を検出するためには、許可されたすべてのオブジェクトに対して、読み取り、更新、削除の動作をテストする必要があります。検出手法は次の2通りです:
どの方法を採用する場合でも、すべてのオブジェクトについて読み取り、更新、削除のチェックを行うことが不可欠です。手動での追加だけでなく、CSVでのインポートなど二次的なルートによる機能も対象に含める必要があります。
防止
Broken Object Level Authorizationの欠陥を防ぐための一般的な対策はこちらにまとめられています。これらの対策により、脆弱性の発生を防ぐか、発生時の影響を低減できます。
アプリの機能が増え、APIが次々と構築される中で、Broken Object Level Authorizationの欠陥はますます広がっています。この脆弱性は深刻であり、サーバーの設定が不十分な場合、リクエスト内の数字を置き換えるだけで簡単に悪用される可能性があるため、ホワイトハッカーによる検証が重要となります。
オブジェクトを扱い、IDを受け取るすべてのエンドポイントでは、必ずObject Level Authorizationを適用し、対象オブジェクトに対して操作を試みる利用者が正しい権限を持つか確認する必要があります。
適切な認証チェックを実施し、権限のないオブジェクトに対する操作を確実に防ぐことが非常に重要です。
弊社のOWASP Top 10の記事もご参照いただき、現在の脆弱性の状況をご確認ください。
最新情報を購読