こんにちは!Webアプリの開発や、セキュリティの勉強を始めたばかりの新人エンジニアの皆さん、日々の開発作業お疲れ様です。
「画面から入力したはずのない情報が、なぜかデータベースの裏側で書き換わっていた……」
実はこれ、モダンなWeb開発でとてもよく起こる、そして攻撃者に一番狙われやすい怖い落とし穴の一つなんです。
今回は、この厄介な仕組みである「Mass Assignment(大量割り当て)」という脆弱性について、専門用語をできるだけ噛み砕いて、身近な例えを交えながら一緒に紐解いていきましょう!
一歩ずつ、安全なコードの書き方を学んでいけば絶対に怖くありません。それでは、さっそく見ていきましょう!
—
1. 「Mass Assignment(大量割り当て)」ってどんな攻撃?
まずは、この脆弱性がどんなものなのか、私たちの身近な「家の鍵と郵便受け」に例えて考えてみましょう。
🏠 身近な例えでイメージしてみよう
想像してみてください。あなたは新しいアパートに引っ越して、管理会社に「名前」と「新しい住所」を紙に書いて提出しました。
この時、もし紙のフォーマットがガバガバだったらどうなるでしょうか?
悪意ある人が、その申込書の隅っこに、こっそり手書きで「この部屋の大家(管理者権限)」というチェックボックスを勝手に書き加えて提出したら……。管理会社がそれをうっかりそのまま受け付けてしまい、あなたが一瞬でそのアパートのオーナーになってしまった!
……これ、現実世界だったら大事件ですよね。でも、セキュリティ対策をしていないWebアプリの世界では、これと同じことが毎日起きています。
🌐 Webアプリの世界での仕組み
Webアプリケーションを作る時、私たちはユーザーが入力したデータ(名前、住所、メールアドレスなど)を、まとめてデータベースに保存するプログラムを書きます。
この時、フレームワーク(便利な開発の土台)の機能によって、「画面から送られてきたデータを、そのまま全部まとめてデータベースの箱にポンと放り込む」という便利なショートカット機能が使われます。これが「Mass Assignment」です。
本来、ユーザーに書き換えてほしくないデータ(例: is_admin(管理者フラグ)や balance(口座残高)など)まで、画面から送られてきたデータと一緒にまるっと受け取ってしまうと、攻撃者がリクエストをちょっと細工するだけで、勝手に自分を「管理者」に昇格させたり、残高を書き換えたりできてしまうのです。
—
2. 攻撃者はどうやって裏をかくの?(仕組みの裏側)
では、攻撃者は具体的にどんな手口を使うのでしょうか?
普段私たちがブラウザで使っている画面の裏側を覗いてみましょう。
例えば、ユーザーのプロフィールを更新する画面があったとします。ブラウザの画面には「ニックネーム」を入力するテキストボックスが1つだけあります。
普通にボタンを押すと、裏側では次のようなデータ(JSON形式のパラメータ)がサーバーに飛んでいきます。
{
"nickname": "親愛なるユーザー"
}
開発初心者の頃は、「画面にはニックネームの入力欄しか作っていないから、サーバーにはこれしか届かないはずだ」と思いがちですよね。
しかし、攻撃者はブラウザの「開発者ツール」や、通信を書き換える専用のツール(Burp Suiteなど)を使って、サーバーに送るデータを次のようにこっそり書き換えてしまいます。
{
"nickname": "親愛なるユーザー",
"is_admin": true
}
サーバー側のプログラムが、届いたデータを「おっ、全部まとめてデータベースに入れちゃおう!」と丸ごと処理する設定(Mass Assignmentを許可した状態)になっていると、なんと is_admin が true に書き換わり、そのユーザーは一瞬でシステムの管理者権限を手に入れてしまうのです……!これがこの脆弱性の恐ろしいところです。
—
3. 脆弱なコードと安全なコードを見比べてみよう
百聞は一見に如かず。PHP(Laravelなどのフレームワークをイメージした疑似コード)を例に、何がダメでどう直すべきなのかを見ていきましょう。
❌ 危険なコード例(すべてを受け入れてしまう)
以下のコードは、「画面から送られてきたデータをそのまま全部データベースに保存する」という危険な状態です。
public function updateProfile(Request $request) {
// ユーザーIDを取得
$user = Auth::user();
// 【危険!】リクエストに含まれるデータをすべてそのまま代入・保存している
// 攻撃者がリクエストに "is_admin": true を混ぜて送ると、そのまま管理者になってしまう!
$user->update($request->all());
return response()->json(['message' => 'プロフィールを更新しました!']);
}
この書き方だと、開発者が意図しないパラメータ(role や is_admin、credits など)がリクエストに含まれていた場合、それらもまとめてデータベースに反映されてしまいます。
⭕️ 安全なコード例(受け取る門番をしっかり決める)
では、どうすれば安全になるでしょうか?答えは簡単です。「受け取ってよいデータ(ホワイトリスト)」を明示的に指定するのです。
public function updateProfile(Request $request) {
// ユーザーIDを取得
$user = Auth::user();
// 【安全!】変更を許可するパラメータを明示的に絞り込む(ホワイトリスト方式)
// これにより、もし攻撃者が "is_admin" などをこっそり混ぜて送ってきても、
// Laravel(フレームワーク)が自動的に無視してくれます。
$validatedData = $request->validate([
'nickname' => 'required|string|max:50',
'bio' => 'nullable|string|max:200',
]);
// 許可された安全なデータだけを使って更新する
$user->update($validatedData);
return response()->json(['message' => 'プロフィールを更新しました!']);
}
このように、validate や only といった機能を使って、受け取るデータを厳しく制限することを、セキュリティの世界では「ストロング・パラメータ(Strong Parameters)」や「ホワイトリスト方式の採用」と呼びます。
—
4. 実務で役立つ!ペネトレーションテスト(診断)の視点
もし皆さんが、自分たちが作ったアプリや、テスト環境のアプリに対して「Mass Assignmentの脆弱性が隠れていないか」をチェック(ペネトレーションテスト)したい場合は、次のポイントを確認してみてください。
1. APIのリクエストを観察する
- ユーザー情報、商品情報、注文情報などを「作成(POST)」または「更新(PUT/PATCH)」する時のAPI通信をブラウザの開発者ツール(ネットワークタブ)でキャプチャします。
2. 隠しパラメータを追加してみる
- リクエストのJSONデータに、通常は画面に存在しないはずのパラメータ(例:
"role": "admin","status": "approved","price": 0など)を意図的に追加して送信してみます。
3. レスポンスとデータベースを確認する
- サーバーがエラーを出さずにリクエストを受け入れた後、データベースや自分のアカウントの権限を確認し、値が勝手に書き換わっていれば脆弱性が存在することになります。
—
まとめ:安全なアプリケーションへの第一歩
Mass Assignmentによる属性改ざんは、フレームワークの「便利機能」の裏を突いた、非常にシンプルでありながら破壊力のある攻撃です。
「画面に項目を作っていないから大丈夫」という思い込みを捨て、「サーバーに届いたデータは、たとえ隠し項目であっても信用しない」というゼロトラスト(信頼しない)の意識を持つことが、プロのエンジニアへの第一歩になります。
今日からコードを書くときは、「このデータは本当にユーザーが自由に変更していいものだっけ?」と立ち止まり、しっかりと受け取る門番(バリデーションやホワイトリスト)を設定するように心がけましょう!
一歩ずつ、安全なアプリケーション作りを楽しんでいきましょうね。それではまた次回のセキュリティ解説でお会いしましょう!
コメント