【入門編】APIにおけるマスアサインメント(Mass Assignment)脆弱性 – アプリケーションセキュリティ & 安全な開発防御ガイド

こんにちは。現場で泥臭いインシデント対応に明け暮れながら、コードの裏側にある「悪意の形」を追い続けているセキュリティエンジニアです。

今日は、初心者エンジニアの皆さんが一度は陥る、けれど絶対に放置してはいけない「マスアサインメント(Mass Assignment)」という落とし穴についてお話しします。

「XSS(クロスサイトスクリプティング)」という言葉は聞いたことがあっても、この「マスアサインメント」は少し地味で、でも破壊力は抜群。例えるなら、家の鍵をかけたはずなのに、裏口の勝手口を「開けっ放しにしていいよ」と許可証を渡してしまっているような状態です。

一歩ずつ、紐解いていきましょう。

—

1. 家の鍵をかける「だけ」では足りない理由

想像してみてください。あなたは自宅(アプリケーション)の玄関に、最高級のセキュリティ錠(認証・認可)をつけました。

しかし、ある日、配送業者さんから「荷物を置くから、勝手口も開けておいて」と言われます。あなたは親切心で、勝手口の鍵を「いつでも自由に出入りOK」の設定にしてしまいました。

これがマスアサインメントの正体です。

Webアプリケーションでは、画面から送られてきたデータをそのままデータベースのモデルに保存する「便利な機能」があります。開発者が「名前」や「メールアドレス」だけ更新してほしいと思っていても、プログラムが気を利かせて「送られてきたデータ全部をモデルに上書き」してしまうのです。

攻撃者はこう狙う

もし、ユーザー情報に is_admin(管理者権限フラグ)という項目があったらどうでしょう?
攻撃者は、普通にプロフィールを更新するフリをして、リクエストデータにこっそり {"name": "田中", "is_admin": true} というデータを混ぜ込みます。

プログラムがそれを「全部更新してね」と受け取ってしまうと……なんと、そのユーザーは一瞬でシステム管理者になってしまうのです。

—

2. 脆弱なコードの「うっかり」例

多くのフレームワーク(Ruby on Rails, Laravel, Springなど)には、開発を楽にする便利な機能があります。しかし、それが仇となることがあります。

// 脆弱な例:受け取ったリクエストをそのままモデルに放り込む(危険!)
app.post(‘/profile/update’, (req, res) => {
const user = User.findById(req.user.id);

// 警告!req.bodyの中身をチェックせずにそのまま更新している
// もしreq.bodyに { “is_admin”: true } が入っていたら…?
user.update(req.body);

res.send(“更新しました!”);
});

このコードは、まさに「勝手口を誰でも開けられるようにしている」状態です。

—

3. 泥棒を入れないための「DTO」という門番

では、どうすればいいのでしょうか? 答えは簡単、「渡されたものすべてを信じない」ことです。

ここで登場するのがDTO(Data Transfer Object)という概念です。「門番」を一人雇うと考えてください。門番は、届いた荷物の中から「許可されたもの」だけを受け取り、それ以外はゴミ箱に捨ててくれます。

DTOを使った安全な実装例

// 安全な例:更新していいフィールドだけを明示的に抽出する
app.post(‘/profile/update’, (req, res) => {
const user = User.findById(req.user.id);

// DTO(許可リスト)を使って、必要なデータだけを取り出す
const updateData = {
name: req.body.name,
email: req.body.email
// is_admin はここに含まれていないので、攻撃者が送っても無視される!
};

user.update(updateData);
res.send(“安全に更新されました!”);
});

このように、「モデルに直接流し込むな、DTOでフィルタリングせよ」というのが、私たちセキュリティエンジニアの鉄則です。

—

4. XSSとセットで考える「防犯の意識」

冒頭で触れた「XSS(クロスサイトスクリプティング)」も、実は同じ「信頼の欠如」から生まれます。XSSは「ユーザーの入力値をそのまま画面に表示してしまう(実行させてしまう)」脆弱性ですよね。

  • XSS: ユーザーの入力を「命令」として実行させてしまう。
  • マスアサインメント: ユーザーの入力を「データベースの権限」として書き換えてしまう。

どちらも「外部からの入力を、アプリケーションの内部ロジックの一部として信じ切っている」ことが原因です。

—

最後に:セキュリティは「疑う」ことから始まる

技術が進歩しても、攻撃者の狙いは常に「開発者のうっかり」です。「このくらい大丈夫だろう」「フレームワークが守ってくれるだろう」という油断が、一番の抜け穴になります。

今日から皆さんのコードを見直してみてください。
「このリクエストパラメータ、本当にそのまま保存しても大丈夫?」と自問自答するだけで、あなたのシステムは一気に堅牢になります。

セキュリティは、一度やって終わりではありません。日々の小さな「門番」の積み重ねが、ユーザーを守る最強の盾になるのです。一緒に、安全で頼もしいアプリケーションを育てていきましょう!

何か具体的な実装で悩んだら、いつでもまた聞きに来てくださいね。現場の知見をフル活用してアドバイスします。

コメント

タイトルとURLをコピーしました