はじめに
セキュリティに問題があると、大変なことになります。
普通のバグは不便で済むこともありますが、セキュリティの穴はアカウント乗っ取り、情報漏えい、サービス停止など、取り返しがつかない形で表に出やすいのです。
そうした重大な事故を未然に防ぐために、本記事ではOWASP Top 10:2025を参考にしながら、初心者でも「どこが危ないか」「何をすれば防げるか」が分かる形で整理していきます。
OWASP Top 10:2025とは
OWASP Top 10は、Webアプリで起きやすく被害が大きいセキュリティ事故パターンを、10カテゴリに整理したものです。
10カテゴリ一覧
- A01 Broken Access Control
- A02 Security Misconfiguration
- A03 Software Supply Chain Failures
- A04 Cryptographic Failures
- A05 Injection
- A06 Insecure Design
- A07 Authentication Failures
- A08 Software or Data Integrity Failures
- A09 Security Logging and Alerting Failures
- A10 Mishandling of Exceptional Conditions
以降、各カテゴリを
1)何が起きるか → 2)よくある例 → 3)対策 → 4)用語メモ
の順でまとめます。
A01 Broken Access Control(アクセス制御の不備)
1) 何が起きるか
ログインしているかどうかではなく、そのユーザーがその操作やそのデータにアクセスして良いかの判定が壊れている状態です。
画面を隠していても、APIやURLを直接叩かれると突破されるのが典型です。
2) よくある例
- URLのidを変えただけで他人の情報が見える(IDOR)
- 一般ユーザーが管理者用APIに到達できる
- 自分以外の注文や投稿を更新削除できる
3) 対策
- 権限チェックは必ずサーバー側で行う(フロントの制御は信用しない)
- deny by default(原則拒否)で、許可する操作だけ通す
- レコード単位で所有者チェックをする(このuserがこのデータを触ってよいか)
- 権限エラーをログに残し、連発する場合はアラートにつなげる(A09と連動)
4) 用語メモ
- アクセス制御:誰が何をして良いかを決めて守る仕組み(ログインとは別)
- API:画面の裏でサーバーにお願いする窓口。URL直打ちで叩けることがある
- URL直打ち:ボタンを押さずに、アドレス欄に直接リンクを入れてアクセスすること
- IDOR:他人のデータIDに差し替えるだけで見えてしまう状態
- deny by default:原則は全部拒否して、必要なものだけ許可する考え方
A02 Security Misconfiguration(セキュリティ設定ミス)
1) 何が起きるか
アプリやサーバーやクラウドの設定が安全な状態になっておらず、穴が空いたまま公開される問題です。
本番環境のうっかりが多く、被害が大きくなりがちです。
2) よくある例
- 本番でデバッグON、スタックトレースが表示される
- 使ってない管理画面やサンプルが残っている
- クラウドストレージが意図せず公開設定になっている
- CORSやセキュリティヘッダが弱い、未設定
3) 対策
- 開発用と本番用の設定を分ける(本番は安全側をデフォルトに)
- 不要な機能やサービスを消す、使わないポートを閉じる
- 設定をコード化してレビュー可能にする(IaCや設定ファイルの管理)
- 秘密情報(APIキーなど)をコードに直書きしない。権限は最小化
4) 用語メモ
- 本番環境:ユーザーが実際に使う公開環境
- デバッグON:開発者向けの詳しいエラー表示を出す設定(本番で危険)
- スタックトレース:エラー原因の履歴。攻撃者にもヒントになる
- CORS:別サイトからAPIを呼べるかのルール。広げすぎると悪用されやすい
- セキュリティヘッダ:ブラウザを安全寄りに動かすための追加情報
A03 Software Supply Chain Failures(サプライチェーンの失敗)
1) 何が起きるか
自分のコードが正しくても、依存ライブラリ、開発端末、CI/CD、配布経路が侵害されると、悪意あるコードや改ざん成果物が混入します。
2) よくある例
- 依存パッケージが乗っ取られ、アップデートに悪意が混じる
- CIのトークンが漏れて、ビルド成果物が差し替えられる
- リリース権限が強すぎて、1人の誤操作や侵害で即本番反映される
3) 対策
- 依存関係のバージョンを固定する(lockfileを使う)
- 依存関係の脆弱性スキャンを定期実行する(自動化が理想)
- CI/CDの権限を最小化し、秘密情報の取り扱いを厳格にする
- リリース手順にレビューと承認を入れる。段階リリースも検討する
4) 用語メモ
- サプライチェーン:部品(ライブラリ)・道具(CI)・配布まで含む供給の流れ全体
- 依存ライブラリ:自分のアプリが使う外部の部品
- lockfile:使う部品のバージョンを固定するファイル(例:package-lock.json)
- CI/CD:自動テスト・自動ビルド・自動リリースの仕組み
- トークン:自動化がログインに使う合言葉。漏れると権限を奪われる
A04 Cryptographic Failures(暗号の失敗)
1) 何が起きるか
暗号化が適用されていない、方式が弱い、鍵管理が雑などの理由で、機密情報が漏えいしたり改ざんされたりします。
パスワードや個人情報を扱うなら最優先で整える領域です。
2) よくある例
- HTTPSが強制されていない
- パスワードを平文で保存している
- 弱いハッシュや古い方式を使っている
- 鍵をソースコードやリポジトリに入れてしまう
3) 対策
- 通信はHTTPS(TLS)を前提にし、HTTPを許可しない
- パスワードは専用のハッシュ方式で保存する(例:bcrypt/Argon2/PBKDF2)。自作しない
- 鍵は安全な保管場所で管理する(環境変数だけでなく専用ストアも検討)
- 暗号は暗号化対象、鍵、運用(ローテーション)までセットで設計する
4) 用語メモ
- HTTPS/TLS:通信を盗み見・改ざんされにくくする仕組み
- 平文:そのまま読める文字(暗号化されていない状態)
- ハッシュ:元に戻せない変換(パスワード保存に使う)
- 鍵:暗号のカギ。ここが漏れると暗号が意味を失う
- ローテーション:鍵を定期的に交換する運用
A05 Injection(インジェクション)
1) 何が起きるか
ユーザー入力がデータではなく命令として解釈され、DBやOSやブラウザ側で不正実行される問題です。
代表例はSQLインジェクションとXSSです。
2) よくある例
- SQLインジェクションでDBから情報を抜かれる、書き換えられる
- XSSで他人のブラウザ上でスクリプトが動き、Cookieや画面操作が盗まれる
- コマンドインジェクションでサーバー上のコマンドが実行される
3) 対策
- SQLは必ずパラメータ化クエリ(プレースホルダ)を使う。文字列連結で作らない
- HTMLに表示する値は適切にエスケープする(テンプレートの自動エスケープを理解する)
- 入力検証は許可リスト型で行う(想定外を弾く)
- コンテキスト別のエスケープを意識する(HTML、属性、URL、JS文字列で違う)
4) 用語メモ
- SQL:データベースに問い合わせる言語
- XSS:入力がHTMLに混ざり、他人のブラウザでスクリプトが動く
- Cookie:ログイン状態などをブラウザに持たせる仕組み(盗まれると危険)
- パラメータ化クエリ:SQLの穴埋めを安全に行う仕組み
- エスケープ:記号を無害化して表示すること
A06 Insecure Design(安全でない設計)
1) 何が起きるか
実装ミス以前に、仕様や設計が攻撃に弱い状態です。
後から直すとコストが大きいので、最初の段階で潰すと効果が高い領域です。
これは具体的なセキュリティの話ではなく、考え方を気をつけようねという話に近いと思います。
2) よくある例
- 重要操作に回数制限がなく総当たりが成立する
- 認証や権限が仕様に曖昧で、抜け道ができる
- 失敗時の挙動が未定義で、例外条件で想定外の成功が起きる
3) 対策
- 重要フロー(ログイン、権限、決済、設定変更)に対して攻撃者目線で考える(脅威モデリング)
- 仕様に制限を入れる(回数制限、二段階確認、クールダウン、監査ログ)
- 安全なデフォルトを決める(エラー時は拒否、公開範囲は最小)
4) 用語メモ
- 設計:実装前に決めるルール。ここが弱いと実装が正しくても破られる
- 脅威モデリング:攻撃者ならどこを狙うかを先に洗い出す作業
- 安全なデフォルト:迷ったら安全側(拒否・非公開・最小権限)に倒す
A07 Authentication Failures(認証の失敗)
1) 何が起きるか
ログイン、セッション、トークン、パスワードリセットが弱く、なりすましが成立します。
漏えいパスワードの使い回しや総当たりに耐えられない設計が多いです。
2) よくある例
- ログイン試行の回数制限がなくブルートフォースされる
- セッションIDが盗まれる、固定される、無効化されない
- パスワードリセットが推測しやすい
3) 対策
- 可能ならMFAを導入する
- ログイン失敗回数制限、遅延、IPや端末単位の防御を入れる
- セッションはログイン後に再発行し、Cookie属性を適切に設定する(SameSite)
- ログアウトや期限切れで確実に無効化する
4) 用語メモ
- 認証:あなたが誰かを確認すること(ログイン)
- MFA:2段階認証。パスワードが漏れても突破されにくい
- セッションID:ログイン中であることを示す番号(盗まれると成りすまし)
- トークン:ログイン状態を示す文字列(APIで使われることが多い)
- SameSite:他サイト経由でCookieが送られにくくなる設定
A08 Software or Data Integrity Failures(ソフトやデータの整合性の失敗)
1) 何が起きるか
「改ざんされているのに、本物だと信じて処理してしまう」問題です。
アプリは外部から届くもの(アップデートファイル、Webhook、設定ファイル、キャッシュ、バックアップ、連携先のデータなど)を受け取りますが、その中身が途中で書き換えられても 確認しない と、攻撃者の都合のいい内容をそのまま実行・保存してしまいます。
イメージ:宅配の箱がすり替わっているのに、開封確認せず中身をそのまま使う。
A03(サプライチェーン)は「供給側(ライブラリ/CI/配布)がやられる」
A08は「受け取ったものを検証せず信じる」
2) よくある例
- 更新ファイル(アプリ/プラグイン等)を署名確認せずに適用する
- Webhookや外部APIのデータを「連携先だから安全」と決めつけて、そのまま重要処理に使う
- 危険な形式のデータをデシリアライズして、意図しない処理が動く(RCEなどにつながる)
3) 対策
- 重要なファイルやデータは 署名(署名付き) か ハッシュ で「改ざんされていない」ことを確認してから使う
- 外部入力(Webhook/外部API/アップロード)は 信用せず検証 してから使う(形式、範囲、期待する送信元など)
- 更新・配布・取り込みの境界(CDN、ストレージ、CI、受信API)に 検証ポイント を置く
- デシリアライズは「必要最小限」。可能なら安全な形式に寄せ、どうしても必要なら 署名付きデータのみ許可 にする
4) 用語メモ
- 完全性(Integrity):データやコードが改ざんされていない状態
- 署名(デジタル署名):配布元が本物で、途中で書き換えられていないことを確認する仕組み
- ハッシュ検証:中身が1文字でも変わると値が変わる性質で改ざん検知する
- 信頼境界:ここから先の入力は「信用しない」と決める境目(外部連携やアップロードは境界の外)
- デシリアライズ:文字列/バイト列→オブジェクトに戻す処理。形式によっては危険になり得る
A09 Security Logging and Alerting Failures(ログとアラートの失敗)
1) 何が起きるか
攻撃されても気づけない、気づいても動けない状態です。
ログがあってもアラートがなければ、発見が遅れて被害が拡大します。
2) よくある例
- ログイン失敗が記録されない
- 権限エラーや重要操作のログがない
- ログはあるが通知されず誰も見ない
- 誤検知が多すぎて本物が埋もれる
3) 対策
- 監査すべきイベントを決めてログ化する(認証、権限、重要操作、設定変更)
- ログの保全と集中管理を行う(改ざん耐性、保存期間)
- 異常の条件を決めてアラートを出す(連続失敗、権限エラー急増など)
- アラートを受けた後の手順(初動、連絡、封じ込め)を用意する
4) 用語メモ
- ログ:何が起きたかの記録
- 監査ログ:後で追跡できるように重要イベントを残すログ
- アラート:異常を通知して、対応を始められる状態にすること
- 集中管理:ログを1か所に集めて守ること(消されにくくする)
- 誤検知:本当は問題ないのに鳴る通知。多いと誰も見なくなる
A10 Mishandling of Exceptional Conditions(例外条件の扱いミス)
1) 何が起きるか
「うまくいかなかった時(エラー・欠落・タイムアウト・障害)に、システムが安全に止まれない」問題です。
本来は失敗したら「拒否」「中断」「元に戻す」べきなのに、例外処理が雑だと 通ってはいけない処理が通る(fail open)、内部情報が漏れる、データが壊れる、二重処理が起きる…といった事故になります。
イメージ:レジが故障したのに「0円で購入OK」になってしまう。
2) よくある例
- 必須パラメータが抜けた時に、権限チェックがスキップされる(本来は拒否なのに通る=fail open)
- 例外メッセージに 内部情報(ファイルパス、SQL、設定名、秘密のヒント)が表示される
- 途中で失敗したのに「成功」扱いになって データが中途半端に更新される(ロールバック漏れ)
- タイムアウト後に再試行が走って 二重処理(二重課金、在庫二重減算)が起きる
- 外部連携が落ちた時に「とりあえずOK」で進めて、後で整合性が壊れる
3) 対策
-
失敗したら基本は拒否(fail closed) にする
- 例外が起きたら「権限なし扱い」「処理中断」「安全側のエラー」に倒す
- エラー表示は ユーザー向けは短く一般的に、詳細は サーバーログにだけ残す
- 画面:
処理に失敗しました。再度お試しください。 - ログ:例外名、スタックトレース、リクエストID、ユーザーIDなど
- 画面:
- 重要処理(課金、在庫、権限変更)は 途中失敗で元に戻るようにする
- DBトランザクション、ロールバック
- 再試行がある処理は 二重実行されても壊れないようにする(冪等性)
- 「同じ注文IDは1回だけ反映」みたいな仕組み
-
異常系テストを入れる
- 必須項目欠落、権限不足、タイムアウト、重複送信、外部API失敗
4) 用語メモ
- 例外条件:正常じゃない状態(欠落、障害、タイムアウト、想定外入力など)
- fail open:エラー時に「通してしまう」こと(危険)
- fail closed:エラー時は「拒否する」こと(安全側)
- ロールバック:途中で失敗したら変更を元に戻すこと
- 冪等性:同じリクエストを複数回処理しても結果が1回と同じになる性質
- 内部情報:攻撃のヒントになる情報(パス、SQL、設定名、秘密の手がかり等)
最小チェックリスト
- APIごとに権限チェックがある(所有者確認含む)
- ログインは回数制限とセッション再発行がある
- 本番でデバッグOFF、不要機能OFF、秘密情報は安全管理
- SQLはパラメータ化、出力はエスケープ
- 認証失敗、権限エラー、重要操作をログに残し、異常を通知できる
- エラー時は拒否して安全側に倒れ、例外詳細は外に出さない