1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IDORとは?実装ミスで起きるアクセス制御の問題を理解する

1
Posted at

はじめに

例えば、自分のユーザー情報を見るためのAPIがあるとします。

GET /users/1

この「1」の部分を「2」に変えたらどうなるでしょうか。

もしそのまま他人の情報が見えてしまうなら、それはバグです。
そして、このタイプの問題は実務でもよく起きます。

この記事では、この問題がなぜ起きるのかをコードで確認しながら整理していきます。


まずは何が起きているのか

次のようなAPIを考えます。

GET /users/1

レスポンス:

{
  "id": 1,
  "name": "Taro"
}

特に変わったことはしていない、よくあるAPIです。


問題のある実装

サーバー側のコードがこうなっていたとします。

<?php

$id = $_GET['id'];

$user = findUserById($id);

echo json_encode($user);

このコード、動きとしては正しいです。

指定されたIDのユーザーを取得して返しているだけです。


何が問題か

この状態でログインしているユーザーが

GET /users/2

のようにリクエストすると、どうなるか。

→ そのままユーザー2の情報が返ってきます。

つまり、

「ログインしているユーザーが誰か」と「取得するデータ」が結びついていない

状態です。


なぜこうなるか

このコードは

  • データを取得する処理

しかしていません。

一方で、

  • そのデータにアクセスしていいか

は一切確認していません。

ここが抜けると、IDを変えるだけで他人のデータにアクセスできてしまいます。


修正する

やることはシンプルで、「誰のデータか」をチェックします。

<?php

session_start();

$userId = $_SESSION['user_id'];
$targetId = $_GET['id'];

if ($userId != $targetId) {
  http_response_code(403);
  exit;
}

$user = findUserById($targetId);

echo json_encode($user);

これで、自分のデータ以外にはアクセスできなくなります。


よくあるパターン

この問題は、特別な場面だけで起きるわけではありません。

例えば:

  • ユーザー情報
  • 注文履歴
  • ファイルダウンロード
  • 管理画面

「IDを指定して何かを取得する」処理がある場所なら、どこでも起きます。


IDを隠しても意味がない

たまに

/users/1 → /users/aj3f9k

のようにIDを隠すケースがあります。

これ自体は悪くないですが、これだけでは解決しません。

アクセス制御がなければ、値を推測された時点で同じ問題が起きます。


まとめ

今回の問題は、特別な攻撃というより

「アクセス制御を書いていない」

ことが原因です。

ログインしているかどうかだけでなく、

「そのデータにアクセスしていいのか」

まで含めて実装する必要があります。

このあたりを意識しておかないと、気づかないうちに穴ができるので注意が必要です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?