玄関の鍵だけじゃ足りない?APIを守る「JSONスキーマ」という最強の番人
こんにちは!セキュリティの世界へようこそ。
「XSS(クロスサイトスクリプティング)」という言葉、一度は耳にしたことがあるかもしれませんね。「Webサイトに悪意あるスクリプトを仕込まれる攻撃」のことですが、実はこれ、皆さんが毎日書いているAPIの「ちょっとした油断」から入り込まれることが多いんです。
今日は、新人のエンジニアさんでも明日からすぐ実践できる、「JSONスキーマによる厳格なバリデーション」という強力な守り方について、身近な例えを交えてお話ししますね。
—
1. なぜ「APIの入り口」が狙われるのか?
まずは、泥棒の視点に立ってみましょう。
あなたの家(Webアプリ)には、頑丈な玄関の鍵(SSL/TLS通信)がかかっています。でも、もし「裏口の小窓」から、名乗ってもいない怪しい人が「これ、届け物です」と適当な小包を投げ込んできたらどうでしょう?
APIにおける「入力」は、まさにこの「投げ込まれる小包」です。
「JSONなら何でも受け入れるよ!」という緩いAPIは、泥棒にとって最高のカモです。攻撃者は、名前の欄に悪意あるスクリプト(など)を紛れ込ませて、あなたのサイトの利用者のブラウザを乗っ取ろうとします。これがXSSの入り口です。
2. 「JSONスキーマ」は、最強の受付係
では、どう守ればいいのでしょうか?
一番簡単なのは、「受け取る小包の中身を、受付で1つずつ検品する」ことです。これを技術的に実現するのが「JSONスキーマ」です。
JSONスキーマとは、「このAPIでは、こういうデータ形式しか受け付けませんよ!」というルール表のこと。「名前は10文字以内の文字列であること」「年齢は整数であること」といったルールを定義し、それに合わないものは「お断り!」と門前払いする仕組みです。
実装例:JSONスキーマで「不正」を弾く
例えば、ユーザー登録APIで「名前」を受け取る場合、以下のように定義します。
{
“type”: “object”,
“properties”: {
“username”: {
“type”: “string”,
“minLength”: 1,
“maxLength”: 20,
“pattern”: “^[a-zA-Z0-9]+$” // 英数字のみ許可!これだけで攻撃コードを排除できます
},
“age”: {
“type”: “integer”,
“minimum”: 0
}
},
“required”: [“username”], // 名前がないと絶対に受け付けない!
“additionalProperties”: false // 定義していない余計なデータはすべて拒否!
}
この「additionalProperties: false」が重要です。これを入れておかないと、攻撃者は定義外のフィールドに悪意あるコードを詰め込んで送ってくるかもしれません。「決まったもの以外は一切受け取らない」という潔さが、セキュリティの鉄則ですよ。
3. なぜ「型チェック」がXSSに効くのか?
「えっ、型をチェックするだけでXSSが防げるの?」と思うかもしれませんね。
実は、XSS攻撃の多くは、本来「文字列」であるはずの場所に「HTMLタグ」や「JavaScriptの命令文」を混ぜ込むことで成立します。
スキーマで「英数字しかダメ」「文字数は20文字まで」とガチガチに制限していれば、攻撃者が準備した「長いスクリプト文字列」は、APIに届いた瞬間に「ルール違反です」と弾かれます。つまり、攻撃コードがデータベースや画面に到達する前に、入り口で消し去ってしまうというわけです。
4. 今日から始める「一歩先の防犯」
現場で開発をしていると、「とりあえず動けばいいや」とバリデーションを疎かにしたくなる気持ち、よく分かります。でも、一度そこを突破されると、お客様の個人情報が盗まれたり、Webサイトが改ざんされたりと、取り返しのつかない事態になりかねません。
まずは、皆さんが作っているAPIで、以下の3つをチェックしてみてください。
1. 型を絞る: 文字列なのか、数値なのか、明確に定義していますか?
2. 長さを制限する: 不必要に長い文字列を受け入れていませんか?
3. 余計なデータは捨てる: additionalProperties: falseを設定していますか?
これらを守るだけで、あなたのAPIは泥棒にとって「攻略しにくい、面倒な家」に変わります。セキュリティは、一度にすべて完璧にする必要はありません。まずは「入り口の検品」から、一歩ずつ一緒に強化していきましょう!
—
【編集後記】
セキュリティは「守り」ですが、同時に「ユーザーへの誠意」でもあります。皆さんが書くそのコードが、誰かの大切な日常を守っているということを、ぜひ忘れないでくださいね。次回の記事では、このデータを「画面に出力する時」の最後の砦、出力エスケープについて深掘りしていきます。お楽しみに!
コメント