認証・認可の脆弱性:ログインとIDOR
他人のデータが見える 水平方向の権限漏れ
この回でやること
同じ役割の別の利用者のデータが読めてしまう崩れ方です。tanaka が別の一般利用者の注文を開く形で、原因が持ち主の確認漏れにあることと、その直し方を扱います。
- 読む 約 8 分
- 最後にクイズ 1 問
このレッスンで学ぶこと
水平方向の権限漏れは、tanakaとsatoのように役割が同じ利用者の間で、持ち主をまたいでデータが読めてしまう欠陥です。この回は2人の注文を並べて、どこで判定が抜けているかを見ます。
読み終えると、番号を1つずらした2回のリクエストから、抜けている確認を指せるようになります。
自分の注文は、正しく開ける
練習用のショップでtanakaとしてログインし、自分の注文履歴から1件開きます。
プレーンテキスト
GET /api/orders/1043 ログイン中 = tanaka
→ 200 {"id":1043,"owner":"tanaka","totalYen":4200}ここまでは正しい動きです。ログインが通っていて、tanakaは自分の注文1043を読んでいます。URLを見ると、注文番号がそのまま/api/orders/1043に出ています。
番号を1つずらすと、他人の注文が出る
同じtanakaのログインのまま、番号を1044に変えて開きます。ログインし直す必要はありません。
プレーンテキスト
GET /api/orders/1044 ログイン中 = tanaka のまま
→ 200 {"id":1044,"owner":"sato","totalYen":98000}返ってきたのはsatoの注文です。tanakaのセッションは正しく、役割も一般利用者のままで、注文1044も実在します。垂直の回で見た役割の判定は、ここでは通っています。それでも他人のデータが出た。抜けているのは、開こうとしている注文の持ち主が、いま操作しているtanaka本人かどうかの確認です。
直し方は、持ち主を突き合わせる
注文を返す前に、その注文のownerと、ログイン中の主体が一致するかを確かめます。一致しなければ拒否します。
プレーンテキスト
GET /api/orders/1044
→ 注文 1044 を引く(owner = sato)
→ owner と操作中の主体 tanaka を比べる
→ 一致しないので拒否して終わりこのとき、拒否の応答を「あなたのものではありません」にしないでください。それでは注文1044が実在することを教えてしまいます。持ち主でない相手には、存在しない番号を開いたときと同じ応答を返します。
持ち主が一致するかは、その注文をデータベースから引いてはじめて分かります。判定を各エンドポイントの中、資源を返す直前に置いてください。入口のログイン確認だけでは、この判定は行われません。