見出し画像

Webアプリケーションセキュリティ入門 ― AI時代だからこそ学ぶべきリスク

はじめに

生成AIを活用した「バイブコーディング」の普及により、短時間でWebアプリケーションを開発できるようになりました。一方で、AIが生成したコードにはセキュリティ上の問題が含まれる可能性が指摘されており、内容を十分に理解せず利用すると、重大な脆弱性を含んだアプリケーションを外部公開してしまう問題があります。

そのため、AIが自動でコードを生成する時代においては、Webアプリケーションにどのようなセキュリティリスクが存在し、どのように対策すべきかを理解しておかなければ、情報漏えいや多額の損害賠償、信用失墜などにつながる可能性があります。



【入力・出力処理】


💀 SQLインジェクション

データベースを不正に参照・変更・削除されるセキュリティリスクです

《 リスク概要 》

SQL文を画面から入力された値をもとに動的に生成している場合、入力値にシングルクオート(')やコメント記号(--)などの特殊文字を含めることで、本来実行されるべきではないSQLを実行されたり、検索条件などのSQLの一部を無効化されたりする可能性があります。その結果、不正なデータの参照・更新・削除などが行われる恐れがある脆弱性です。

《 想定される被害・影響》

  • データベースに保存されている機密情報が不正に閲覧され、情報漏えいにつながる

  • データベース内のデータが不正に追加・更新・改ざん・削除され、情報の完全性や信頼性が損なわれる

  • ストアドプロシージャなどの機能を悪用されることで、データベースサーバ上でOSコマンドが実行され、不正なシステム操作やサーバの乗っ取りにつながる

《 対応方法 》

・プレースホルダ(パラメータ化クエリ)を利用する【原則必須】
SQL文を動的に組み立てる場合は、プレースホルダ(パラメータマーカー)を使用して実装することを基本とします。これにより、入力値がSQL文の一部として解釈されることを防ぎ、SQLインジェクションを効果的に防止できます。

// Node.js
const result = await db.query(
  "SELECT id, name FROM users WHERE name = $1",
  [String(req.body.name ?? "")]
);
res.json(result.rows);
# Python
cursor.execute(
    "SELECT id, name FROM users WHERE name = %s",
    (str(request.json.get("name", "")),),
)
rows = cursor.fetchall()

・文字列連結でSQLを組み立てる場合は入力値を適切にエスケープする【非推奨】
やむを得ずSQL文を文字列連結で生成する場合は、入力値がSQL文として解釈されないよう、データベース製品に応じたエスケープ処理を実施します。プレースホルダ対応されていれば、この対応は不要です。

推奨されていないため、安全性を考えるならこの対策をしないで、プレースホルダ/パラメータ化を行う実装をしてください。

補足
入力値の型チェックが適切に実施され、文字列が必ずシングルクォーテーションで囲まれる設計であれば、; や -- の除去は不要となる場合があります。 これらの文字が入力される必要のない項目については、バリデーションエラーとする、または空文字へ置換する方法でも問題ありません。 エスケープ処理に依存する設計は避け、可能な限りプレースホルダを利用してください。

・SQL文をリクエストから直接受け取って実行しない【必須】
画面項目、隠し項目、JavaScript変数などを含め、SQL文そのものをリクエストパラメータとして受け取り、そのまま実行してはなりません。SQL文は必ずサーバ側で固定のテンプレートとして管理し、入力値はパラメータとして設定してください。


💀 HTMLインジェクション

不正なHTMLタグを挿入され、表示内容や操作を改変される脆弱性です

《 リスク概要 》

画面への入力値やリクエストパラメータなどを適切に処理せずHTMLへ出力すると、利用者が入力した文字列が単なる文字としてではなく、HTMLタグとしてブラウザに解釈される場合があります。攻撃者は、入力フォームやURLのリクエストパラメータなどにHTMLタグを含めることで、画面上に偽のメッセージ、リンク、入力フォーム、画像などを表示させ、正規のWebサイトの一部であるかのように見せることができます。

なお、挿入した内容によってJavaScriptなどのスクリプトを実行できる場合は、HTMLインジェクションではなく、より深刻な「クロスサイトスクリプティング(XSS)」として扱います。

《 想定される被害・影響》

  • Webページの表示内容を改変され、利用者に誤った情報を表示される

  • 偽のリンクやボタンを表示され、攻撃者が用意したWebサイトへ誘導される

  • 偽のログイン画面や入力フォームを表示され、利用者自身に認証情報や個人情報を入力させることで情報を窃取される

  • 正規サイトの画面を利用したフィッシングなどに悪用され、Webサイトの信頼性が損なわれる

《 対応方法 》

利用者から受け取った値をHTMLとして出力しない【必須】
利用者から受け取った文字列は、原則としてHTMLではなくテキストとして出力します。Reactなどのフレームワークでは通常、文字列を自動的にエスケープして出力しますが、dangerouslySetInnerHTMLなど、HTMLを直接挿入する機能を利用すると保護が適用されない場合があるため注意してください。

出力先に応じたエスケープ処理を実施する【必須】
利用者から受け取った値をHTMLへ出力する場合は、HTMLの特殊文字を適切にエスケープし、ブラウザからHTMLタグとして解釈されないようにします。

補足
・入力値を単純に禁止文字で除去するだけでは、十分な対策にならない場合があります。
・エスケープは、データを受け取った時点ではなく、HTMLへ出力する際に実施することが重要です。
・業務上HTMLの入力を許可する必要がある場合は、許可するHTML要素や属性を限定し、安全なHTMLサニタイザを利用してください。


💀クロスサイトスクリプティング(XSS)

利用者のブラウザ上で不正な処理を実行される脆弱性です

《 リスク概要 》

利用者から受け取った値を適切に処理せずWebページへ出力することで、悪意のあるJavaScriptなどを利用者のブラウザ上で実行される脆弱性です。攻撃者は、入力フォームやURLのリクエストパラメータなどに悪意のあるスクリプトやHTMLを埋め込みます。その内容がWebサーバーからブラウザへ返却され、スクリプトとして実行されるとXSSが成立します。

これにより、利用者の情報の窃取、不正な画面操作、偽サイトやマルウェア配布サイトへの誘導などに悪用される可能性があります。

《 想定される被害・影響》

  • Cookieやセッション情報が窃取され、利用者になりすましてサービスを利用される「セッションハイジャック」が発生する(詳細:セッションハイジャック)

  • 利用者が入力したID・パスワードやクレジットカード情報などの重要情報が窃取される

  • 偽のログイン画面などへ誘導され、認証情報や個人情報が窃取される

  • 悪意のあるスクリプトによって不正なサイトやマルウェア配布サイトへ誘導され、端末のマルウェア感染など、さらに深刻な被害につながる場合がある

《 対応方法 》

HTMLインジェクション対策を実施する【必須】
利用者から受け取った値をHTMLへ出力する場合は、HTMLインジェクション対策に従い、適切なエスケープまたはサニタイズを実施する。→HTMLインジェクション

JavaScript構文内で、リクエストパラメータやデータベースから取得した値を使用する場合は、適切にエスケープする【必須】
JavaScript構文内で、リクエストパラメータやデータベースから取得した値を変数に設定する場合は、その値がJavaScriptの命令として解釈されないよう、JavaScript文字列用のエスケープ処理を実施する。

下記のような場合、もし name に「"; alert('XSS'); //」がセットされていると…

<script>
var name = "<%= request.getParameter("name") %>";
</script>
var name = ""; alert('XSS'); //";

となり、alert('XSS') が実行されます。

JavaScriptでDOMを操作する際は、HTMLを直接生成・挿入しない【必須】
JavaScriptでDOMを操作する場合は、リクエストパラメータやデータベースから取得した値を innerHTML や insertAdjacentHTML() などでHTMLとして生成・挿入しない。文字列を表示する場合は、textContent など、HTMLとして解釈されないDOM APIを使用する。

Content Security Policy(CSP)を設定する【推奨】
Content Security Policy(CSP)は、ブラウザが読み込み・実行できるコンテンツの取得元や実行方法を制限するためのセキュリティ機能です。
万が一、Webページに悪意のあるスクリプトが埋め込まれた場合でも、CSPを適切に設定することで、外部サイトから取得したスクリプトの実行や、許可していないコンテンツの読み込みを防止できるため、XSSによる被害を軽減できます。

設定例(httpヘッダ)
自サイトから提供されるコンテンツのみを読み込む場合

Content-Security-Policy: default-src 'self';

JavaScriptは自サイトのみ許可し、画像は自サイトとCDNからの取得を許可する場合

Content-Security-Policy:
default-src 'self';
script-src 'self';
img-src 'self' https://cdn.example.com;

注意事項
・CSPはXSSを完全に防止するものではありません。 出力時のエスケープやサニタイズなどの基本対策と組み合わせて利用する必要があります。
・script-src 'unsafe-inline' や script-src 'unsafe-eval' を指定すると、インラインスクリプトや eval() の実行を許可してしまうため、セキュリティが低下します。特別な理由がない限り使用しないでください。
・既存システムへ導入する場合は、まず Content-Security-Policy-Report-Only を利用して違反状況を確認し、問題がないことを確認してから適用することを推奨します。

※ セキュリティ対策は、システムの安全性だけでなく、利用者の利便性や運用性への影響も考慮して選択してください。過度な対策は業務効率やユーザビリティを低下させる場合があるため、リスクに応じた適切なレベルで実施することが重要です。


💀Hiddenフィールドマニピュレーション

利用者に知られてはならないデータや、改ざんされてはならないデータをブラウザの隠し項目(Hiddenフィールド)に保持することで、悪意のある利用者によって閲覧・改ざんされる脆弱性です。

《 リスク概要 》

隠しフィールド(hiddenフィールド)は画面上には表示されませんが、HTMLのソースやブラウザの開発者ツール、通信内容の編集ツールなどを利用することで、利用者が値を確認・変更することが可能です。

そのため、変更されてはならない重要な情報を隠しフィールドに保持し、その値をサーバ側で信頼して処理すると脆弱性となります。攻撃者が隠しフィールドの値を改ざんすると、本来アクセス権限のないデータの閲覧や、不正な登録・更新・削除などが行われる可能性があります。

《 想定される被害・影響》

  • 本来、仕様またはアクセス権限により閲覧できない情報が、不正に閲覧される

  • 本来、仕様またはアクセス権限により変更が許可されていない情報が、不正に登録・更新・削除される

  • 本来、仕様またはアクセス権限により実行が許可されていない画面操作や機能が、不正に実行される

《 対応方法 》

クライアント(ブラウザ)から返却された重要な情報を信用しない【必須】
画面の表示項目や隠しフィールドなど、クライアントへ送信した情報を、そのままサーバ側で信用して処理してはなりません。重要な情報は、リクエストから取得するのではなく、サーバ側で管理している情報を使用します。

取得先の例
データベース
・セッション
・Redisなどのサーバ側キャッシュ
・ワークテーブルや一時データ領域

やむを得ずクライアントへ保持する場合は改ざん対策を行う【推奨】
業務上の都合により重要な情報をクライアントへ保持する必要がある場合は、値の改ざんを検知または防止できる仕組みを導入します。改ざん対策を実施している場合でも、権限チェックなどのサーバ側検証を省略してはいけません。

仕組みの例
電子署名(HMAC等)を付与し、サーバ側で改ざんを検証する。
・暗号化した値を送信し、復号時に整合性を検証する。
・クライアントには一時的な識別子のみを保持し、実データはサーバ側で管理する。

サーバ側で権限・妥当性を再確認する【必須】
画面から受け取った値は信用せず、サーバ側でアクセス権限やデータの妥当性を必ず再確認してください。→IDOR/BOLA

クライアントから送信される値は、画面上で入力できない項目や隠しフィールドであっても改ざんされる可能性があります。そのため、画面で入力できないようにしている項目や、非表示にしている項目であっても、安全であるとは判断せず、サーバ側で必ず再確認してください。

確認内容例
・ログインユーザーが対象データを閲覧・登録・更新・削除する権限を有していること。
・リクエストで指定されたIDやキーが、ログインユーザーに紐付く正当なデータであること。(自社データのみ扱える権限の場合、画面から他社のIDが渡ってないか?など)
・リクエストで送信された値が、業務仕様上許可される値であること。(画面上のラジオボタンやセレクトボックスで選択できない場合でも、不正な操作でそれ以外の値が渡せるため、サーバー側で必ずチェックする)

《 実装上の注意事項》

「一覧画面」から「詳細画面」への遷移
一覧画面から詳細画面へ遷移する際、詳細データのIDなどを画面へ渡すことがあります。このIDを改ざんされると、本来閲覧できないデータへアクセスされる可能性があります。

対応例
サーバ側で対象データの閲覧権限を再確認する。
・IDに電子署名や暗号化などの改ざん対策を施す。
・実際のIDはサーバ側で保持し、画面とは一時的な識別子のみをやり取りする。(選択できるIDの一覧を一時的にサーバー側に保持し、その中にない場合はエラーとするなど)

ReadOnly項目
readonly 属性を付与した入力項目でも、ブラウザの開発者ツールなどを利用すれば値を変更できます。そのため、readonlyだから安全と考えてはいけません。

対応例
画面から送信された変更不可項目の値は、検索・登録・更新・削除などの処理に使用しない。
・変更不可項目は、リクエストで送信された値ではなく、データベースまたはセッションなどサーバー側で保持している値から再取得する。
・画面から送信された値とサーバ側の値を比較し、不一致であればエラーとする。

ファイルダウンロード
ダウンロード対象のファイル名やファイルIDを画面から受け取る場合、改ざんにより別のファイルを取得される可能性があります。

対応例
サーバ側でダウンロード権限を再確認する。
・ファイルIDに改ざん対策を実施する。
・実際のファイル情報はサーバ側で管理する。

ユーザー権限による、特定項目の表示/非表示・入力可/不可制御
JavaScriptで入力項目の活性・非活性やボタンの表示・非表示などを制御するため、ユーザーIDや権限区分などの情報を画面へ渡すことがあります。しかし、画面へ渡した情報は利用者がブラウザの開発者ツールや通信内容を編集するツールなどを使用して変更できるため、サーバ側でその値を信用してはいけません。→認証・認可チェックの不備

例えば、画面では一般ユーザー向けに「削除」ボタンを非表示にしていても、画面へ渡した権限区分を改ざんして「削除」ボタンを表示させ、削除機能を実行しようとする可能性があります。

対応例
・フロントエンドのJavaScriptによる表示制御や入力制御は、画面表示上の利便性を向上させるための補助機能として利用し、バックエンドではこれらの制御が行われていないことを前提として、入力値の妥当性やアクセス権限を確認した上で処理を行う。
・サーバ側の認可処理では、画面から送信された権限情報ではなく、ログインセッションやデータベースなど、サーバ側で管理している権限情報を使用する。

対象となる情報の例
ユーザーID
・グループID
・会社コード
・部署コード
・権限区分
・ロール情報


💀 OSコマンドインジェクション

サーバー上で任意のコマンドを実行される脆弱性です。

《 リスク概要 》

画面の入力値やリクエストパラメータなど、本来はデータとして扱われるべき外部からの入力値が、OSの命令として解釈・実行されてしまう脆弱性です。

入力値にOS上で特別な意味を持つ文字列を組み込まれることで、意図しないOSコマンドを実行され、サーバ上のファイル操作やプログラム実行などの不正な操作を行われる可能性があります。

《 想定される被害・影響》

  • サーバ上で任意のOSコマンドを実行され、実行権限の範囲内でサーバを不正に操作・支配される

  • サーバやデータベースに保存された機密情報を窃取されるほか、重要なデータを改ざん・削除される

  • マルウェアやバックドアなどを不正に設置・実行され、サーバを継続的に遠隔操作される

  • 乗っ取られたサーバを、他のサーバやシステムへの不正アクセス・サイバー攻撃の踏み台として悪用される

  • システムファイルの削除や設定変更、プロセスの停止などにより、サービスやサーバを停止・破壊される

※ 被害の範囲は、Webアプリケーションを実行しているOSユーザーの権限に左右される。高い権限を奪われた場合は、サーバ全体を制御される深刻な被害につながる。

《 対応方法 》

OSコマンドの実行を避ける【原則必須】
Webアプリケーションのバックエンドの処理でシェル(cmd.exe、sh、bashなど)や外部プログラムを直接実行するような実装は、余程のことがない限り避けてください。ファイル操作、圧縮・展開、画像変換などの処理は、OSコマンドではなく、使用しているプログラミング言語やフレームワークが提供するAPI・ライブラリで実装するようにしてください。

外部から受け取った値をコマンド文字列へ直接組み込まない【必須】
画面の入力値、リクエストパラメータ、HTTPヘッダ、Cookie、アップロードファイル名など、外部から受け取った値を文字列連結し、OSコマンドとして実行してはなりません。特に、外部入力を含む文字列をシェルへ渡す実装は避けてください。

やむを得ず外部プログラムを実行する場合は、実行内容を固定する【必須】
外部プログラムの実行が必要な場合は、利用者がコマンド名やオプションを自由に指定できないようにします。

【設定基準】
・実行するプログラムは、サーバ側であらかじめ固定で決め、それ以外を実行できなくする
・利用できる処理やオプションは、許可リストから選択し、文字列としてそのまま渡さないようにする
・入力値はコマンド文字列へ連結せず、引数を個別に渡せる実行APIを使用する
・外部プログラムを実行する場合は、プログラムと引数を分離して指定する
・実行ユーザーには、処理に必要な最小限の権限のみを付与する

《 Pythonでの例 》

import subprocess

dir_name = request_value  # 画面から受け取った値
subprocess.run(
    "cmd.exe /C dir " + dir_name,
    shell=True
)

例えば、画面から次のような値が入力された場合、

logs & del aaa.bat

実質的に、

cmd.exe /C dir logs & del aaa.bat

というコマンドとして解釈される可能性があります。

《Node.jsでの例 》


const { exec } = require("child_process");
const dirName = requestValue; // 画面から受け取った値
exec("cmd.exe /C dir " + dirName);

脆弱性いついてはPythonでの例と同じ


💀 入力値検証の不備

想定外の値を受け入れることで、不正な業務処理やデータ不整合が発生する脆弱性です。

《 リスク概要 》

画面から入力された金額、数量、日付、文字列、選択値などについて、サーバ側で形式や範囲を適切に検証していない場合、業務上想定されていない値を送信される可能性があります。

画面上で入力を制限していても、ブラウザの開発者ツールや通信内容を編集するツールなどを使用すれば、制限を無視した値を送信できます。その値をサーバ側で信用して処理すると、不正な取引やデータ不整合につながる脆弱性となります。

《 想定される被害・影響》

  • 金額や数量に負数、ゼロ、上限を超える値などを指定され、不正な購入、返金、割引、ポイント付与などが行われる

  • 存在しない日付や許可されていない期間を指定され、予約や申請などの業務処理に不整合が発生する

  • 文字数の上限を超えるデータを登録され、画面表示の崩れや処理エラー、データベースへの登録失敗が発生する

  • 画面では選択できない区分や状態を送信され、本来許可されていない処理が実行される

  • 不正な値がデータベースへ保存され、後続処理や他システムとの連携に障害が発生する

《 対応方法 》

サーバ側で入力値を検証する【必須】
画面やリクエストから受け取った値について、サーバ側で型、形式、文字数、範囲、必須入力、選択可能な値などを検証し、業務仕様に合わない値は処理せずエラーとします。

JavaScriptやHTML属性による入力制限は、利用者の入力を補助するための機能として使用し、セキュリティ対策として依存してはいけません。

確認内容例
・金額や数量が数値であり、許可された最小値・最大値の範囲内であること
・日付が正しい形式で、実在する日付や許可された期間であること
・文字列が許可された文字数や形式の範囲内であること
・区分やステータスが、サーバ側で定義した許可リストに含まれていること
・複数の入力項目の組み合わせが、業務上矛盾していないこと

《 Pythonでの例 》

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.post("/orders")
def create_order():
    data = request.get_json()

    price = data["price"]
    quantity = data["quantity"]

    total = price * quantity

    # totalを使って注文処理を実行
    return jsonify({
        "price": price,
        "quantity": quantity,
        "total": total
    })

例えば、次のような値を送信された場合、

{
  "price": 1000,
  "quantity": -10
}

合計金額が -10000 となり、不正な返金処理やポイント付与などにつながる可能性があります。

《Node.jsでの例 》

const express = require("express");

const app = express();
app.use(express.json());

app.post("/applications", async (req, res) => {
  const status = req.body.status;
  const comment = req.body.comment;

  // statusを検証せず、そのまま登録
  await saveApplication({
    status,
    comment
  });

  res.json({ message: "登録しました" });
});

例えば、画面では draft と submitted しか選択できない場合でも、次のような値を送信される可能性があります。

{
  "status": "approved",
  "comment": "不正な申請"
}

その結果、本来は管理者だけが設定できる「承認済み」の状態で登録される恐れがあります。


💀 ディレクトリトラバーサル

ファイルパスを不正に操作され、本来公開していないファイルを閲覧・変更される脆弱性です。

《 リスク概要 》

Webアプリケーションで、利用者から受け取ったファイル名やパスをそのままファイルアクセスに使用すると、../ などを追加して本来の保存先より上のディレクトリへ移動される可能性があります。

例えば、

/download?file=manual.pdf

の file を次のように変更されるケースです。

/download?file=../../config/settings.yml

このような操作により、設定ファイルやソースコードなど、本来公開していないファイルを取得される可能性があります。

また、アップロードやファイル保存処理で同様の問題がある場合は、本来とは異なる場所へファイルを書き込まれる可能性もあります。

《 想定される被害・影響》

  • 設定ファイルやソースコードを閲覧される

  • パスワード、APIキー、接続情報などの機密情報を取得される

  • サーバー上のシステムファイルを閲覧される

  • 本来アクセスできない利用者や組織のファイルを取得される

  • アップロードしたファイルを想定外の場所へ保存される

  • 重要なファイルを上書きされ、システム障害や不正プログラムの実行につながる

《 対応方法 》

利用者からファイルパスを直接受け取らない【必須】
画面やAPIから受け取った文字列を、そのままディレクトリ名やファイルパスとして使用しないようにします。可能であれば、利用者からはファイルIDなどを受け取り、サーバー側で実際のファイルパスへ変換します。

fileId=123
    ↓
サーバー側で検索
    ↓
/data/manual/abc123.pdf

利用者が実際の保存先を自由に指定できない設計が望ましいです。

アクセス可能なディレクトリを限定する【必須】
ファイル名やパスを受け取る必要がある場合は、パスを正規化したうえで、最終的な保存先や参照先が許可されたディレクトリの配下にあることをサーバー側で確認します。

※ 注意 ※
../ や / を含むかどうかだけで判断すると、文字コードの違いやOSごとのパス表現などによって回避される可能性があるため、文字列の単純な禁止だけに依存しないようにしてください。

ファイルへのアクセス権限を確認する【必須】
ファイルを表示・ダウンロードする場合は、パスが正しいことだけでなく、ログイン中の利用者がそのファイルへアクセスする権限を持っていることも確認します。他の利用者や組織のファイルを、ファイル名やIDの変更だけで取得できないようにしてください。→IDOR/BOLA

アップロード先をサーバー側で固定する【必須】
アップロード時に利用者から保存先ディレクトリを自由に指定させず、サーバー側で決めた保存先へ保存します。ファイル名についても、必要に応じてサーバー側で生成した名前へ変更し、利用者から送信されたパス情報をそのまま使用しないようにします。


💀 危険なファイルアップロード

アップロードするファイルの種類や内容を適切に制限していないことで、不正なプログラムの実行や情報漏えいなどにつながる脆弱性です。

《 リスク概要 》

画像や文書などのアップロード機能で、利用者から送られたファイルを十分に確認せず保存すると、実行可能なファイルや悪意のある内容を含むファイルをアップロードされる可能性があります。例えば、画像だけを受け付ける機能に .php、.jsp、HTMLなどをアップロードでき、それがWebサーバー上で実行・表示されると、サーバーの乗っ取りやXSSなどにつながる場合があります。

《 想定される被害・影響》

  • 不正なプログラムをサーバー上で実行される

  • サーバー内のファイルや機密情報を取得される

  • HTMLやSVGなどを利用してXSSを実行される

  • マルウェアをアップロード・配布される

  • 既存ファイルを上書きされる

  • 大容量ファイルによってディスク容量やサーバー資源を圧迫される

《 対応方法 》

アップロード可能なファイル種類を限定する【必須】
業務上必要なファイル形式だけを許可します。例えば画像アップロードであれば、JPEG・PNGなど必要な形式だけを許可し、それ以外は拒否します。

確認は、次のように複数の方法を組み合わせます。

拡張子
.jpg、.png、.pdf など、許可した拡張子だけを受け付ける

Content-Type(MIMEタイプ)
image/jpeg、image/png、application/pdf など、想定した種類か確認する

ファイル内容
ファイル先頭のシグネチャ(Magic Number)などを確認し、実際のファイル形式と一致しているか確認する

Content-Type はリクエスト送信時に変更できるため、Content-Typeだけでファイル種類を判断してはいけません。 また、拡張子だけを書き換えた不正ファイルもあるため、複数の確認方法を組み合わせて判定してください。

ファイル名と保存先をサーバー側で決定する【必須】
利用者から送られたファイル名をそのまま保存せず、UUIDなどを利用してサーバー側でファイル名を生成します。保存先についても利用者に指定させず、サーバー側で決めたディレクトリへ保存します。→ディレクトリトラバーサル

アップロードしたファイルを実行できない場所へ保存する【必須】
可能であれば、アップロードファイルはWeb公開領域の外へ保存します。Webから提供する必要がある場合も、アップロードされたPHPやJSPなどがプログラムとして実行されない構成にしてください。

ファイルサイズを制限する【必須】
アップロード可能なファイルサイズに上限を設定し、大容量ファイルによるディスク容量やサーバー資源の消費を防ぎます。

ファイルサイズの目安
・プロフィール画像など:2~5MB程度
・PDF・Office文書など:10~20MB程度
・大きな画像・資料:20~50MB程度
動画など:用途に応じて個別設計

必要に応じてマルウェア検査を行う【推奨】
利用者がアップロードしたファイルを他の利用者がダウンロードするシステムなどでは、ウイルス対策ソフトやマルウェアスキャンを利用して、不正なファイルを検出します。


💀 NoSQLインジェクション

入力値をNoSQLデータベースの検索条件として不適切に使用することで、検索条件を改ざんされ、不正なデータ取得や認証回避などにつながる脆弱性です。

《 リスク概要 》

MongoDBなどのNoSQLデータベースでは、JSONのような形式で検索条件を指定することがあります。利用者から受け取った値をそのまま検索条件へ渡すと、本来は単なる文字列として扱うべき値に、NoSQLの検索演算子などを含められる場合があります。

例えば、ログイン処理で次のような入力を想定していても、

{
  "username": "user01",
  "password": "password123"
}

攻撃者が文字列ではなく、検索条件を表す値を送信する可能性があります。

{
  "username": "user01",
  "password": { "$ne": null }
}

アプリケーションがこの内容をそのままMongoDBの検索条件として使用すると、$ne が「一致しない」という検索演算子として解釈され、意図していない条件で検索される可能性があります。
つまり、入力値を単なるデータとして扱うべきところを、データベースの検索条件として解釈させてしまうことが問題です。

《 想定される被害・影響》

  • ログイン認証を回避される

  • 本来取得できないデータを検索・取得される

  • 検索条件を変更され、大量のデータを取得される

  • データを不正に変更・削除される

  • データベースの構造や内部情報を推測される

《 対応方法 》

入力値の型と形式をサーバ側で確認する【必須】
文字列として受け取る項目には、オブジェクトや配列などを受け付けないようにします。例えばユーザー名やパスワードを文字列として使用する場合は、受信した値が本当に文字列であることを確認してから処理します。

if (
  typeof req.body.username !== "string" ||
  typeof req.body.password !== "string"
) {
  return res.status(400).end();
}

画面から文字列しか入力できないようにしていても、攻撃者はAPIリクエストを直接変更できるため、サーバ側で確認する必要があります。

入力値をそのまま検索条件として使用しない【必須】
リクエストで受け取ったJSONやオブジェクト全体を、そのままNoSQLデータベースの検索条件へ渡さないようにします。

// 危険な例
users.findOne(req.body);

必要な項目だけを取り出し、アプリケーション側で検索条件を作成します。

// 改善例
users.findOne({
  username: req.body.username
});

利用者から検索演算子を受け取らない【必須】
$ne、$gt、$regex など、NoSQLデータベースの検索方法を変更する演算子を、利用者が自由に指定できる設計にしないようにします。検索条件が必要な場合は、利用可能な検索方法をサーバ側であらかじめ決め、許可した条件だけを使用します。

文字列を組み合わせてクエリを作成しない【必須】
利用者から受け取った値を文字列連結して、JavaScript式やデータベース固有のクエリとして実行しないようにします。特に、NoSQLデータベースの eval やJavaScript実行機能などへ利用者の入力値を渡さないようにしてください。


💀 コードインジェクション・動的実行

利用者から受け取った値をプログラムとして動的に実行することで、攻撃者に任意のコードを実行される脆弱性です。

《 リスク概要 》

Webアプリケーションで、利用者から受け取った値を eval などの動的実行機能へ渡すと、本来は単なるデータとして扱うべき入力がプログラムとして実行される可能性があります。

例えば、JavaScriptで次のような処理を行う場合です。

const result = eval(req.body.expression);

攻撃者が expression の内容を自由に指定できると、想定していた計算式だけでなく、不正なJavaScriptコードを実行される可能性があります。

つまり、外部から受け取った値を「データ」ではなく「実行するコード」として扱ってしまうことが問題です。

《 想定される被害・影響》

  • サーバー上で任意のプログラムを実行される

  • ファイルやデータを閲覧・変更・削除される

  • APIキーや認証情報などの機密情報を取得される

  • アプリケーションの処理を不正に変更される

  • 実行権限によってはサーバー全体を乗っ取られる

実行されるコードは、通常そのWebアプリケーションと同じ権限で動作するため、アプリケーションに強い権限を与えているほど被害も大きくなる可能性があります。

《 対応方法 》

外部から受け取った値をコードとして実行しない【必須】
利用者から受け取った文字列を eval などの動的コード実行機能へ渡さないようにします。

// 危険
eval(req.body.expression);

計算方法や処理内容を選択させる必要がある場合でも、利用者にプログラムそのものを指定させず、サーバー側で許可した処理だけを選択できるようにします。

const operations = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b
};

const operation = operations[req.body.operation];

if (!operation) {
  throw new Error("許可されていない処理");
}

const result = operation(a, b);

実行する関数や処理を利用者に自由に指定させない【必須】
関数名、クラス名、テンプレート、スクリプトなどをリクエストから受け取り、そのまま実行する設計は避けます。必要な場合は、利用できる処理をサーバー側で許可リストとして定義し、その中から選択させます。利用者が関数名や引数を自由に指定できる実装は、任意コード実行につながる場合があります。

動的実行が必要な場合は入力内容を厳格に限定する【条件付き推奨】
どうしても式やスクリプトのような入力を扱う必要がある場合は、汎用的な eval を使用せず、用途専用の安全なパーサーやライブラリを使用し、利用可能な構文・命令・関数を限定します。利用者が自由なプログラムを実行できる仕組みにしないことが基本です。


💀 オープンリダイレクト

利用者から受け取ったURLを確認せずに転送先として使用することで、正規サイトから攻撃者のサイトなどへ自由に転送される脆弱性です。

《 リスク概要 》

ログイン後や処理完了後などに別のページへ移動する機能で、リクエストから受け取ったURLをそのまま転送先として使用すると、攻撃者が外部サイトを自由に指定できる場合があります。

例えば、

https://example.com/redirect?url=https://example.com/mypage

の url を次のように変更できるケースです。

https://example.com/redirect?url=https://attacker.example/

利用者から見ると最初のURLは正規サイトのドメインであるため、信用してリンクを開き、そのまま偽サイトへ誘導される可能性があります。

《 想定される被害・影響》

  • 正規サイトを装ったリンクからフィッシングサイトへ誘導される

  • 偽ログイン画面などでID・パスワードを盗まれる

  • マルウェア配布サイトや不正サイトへ誘導される

  • 正規ドメインを利用してURLの安全性チェックを回避される

  • OAuthなどの認証処理と組み合わせて、認証情報やトークンの窃取につながる

《 対応方法 》

外部から受け取ったURLをそのまま転送先に使用しない【必須】
可能であれば、利用者からURLそのものを受け取らず、サーバ側であらかじめ用意した転送先だけを使用します。

例えば、

redirect=mp

のような識別子を受け取り、

mp → /mypage
sg → /settings

のようにサーバ側で転送先を決定します。

転送可能なURLを許可リストで制限する【必須】
外部URLへの転送が必要な場合は、許可するドメインやURLをあらかじめ決め、その範囲だけを転送できるようにします。文字列が含まれているかのような雑な確認ではなく、URLを正しく解析し、ホスト名などを確認してください。

同一サイト内の転送は相対パスを使用する【推奨】
同じWebサイト内だけで画面遷移する場合は、相対パスを使用し、https://~ など任意の外部URLを指定できない設計にします。ただし、 / から始まっていても、ブラウザでは外部サイトとして解釈されるURL形式があります。そのため、「/ から始まっているから自サイト内」と判断せず、サーバー側で許可した転送先だけを使用してください。

相対パスの例(OK)
/mypage → https://example.com/mypage

外部サイトの例(NG)
//attacker.example/ → https://attacker.example/


💀 サーバーサイドリクエストフォージェリ(SSRF)

利用者が指定したURLなどをサーバーがそのまま利用して通信することで、内部システムや本来アクセスする必要のない接続先へ通信させられる脆弱性です。

《 リスク概要 》

Webアプリケーションには、指定されたURLから画像を取得する機能、Webhook、URLプレビュー、外部サービスとの連携など、サーバー側から別のシステムへ通信する機能があります。

例えば、

利用者
   ↓ URLを指定
Webアプリケーション
   ↓
指定されたURLへサーバーからアクセス

という機能で、利用者が通信先を自由に指定できると、

外部の正規サイト   → 本来の利用
内部システム       → 不正なアクセス
クラウド管理機能   → 不正なアクセス

のように、外部から直接アクセスできない場所へWebサーバーを経由して通信される可能性があります。

サーバーは利用者の端末よりも内部ネットワークや他のシステムへアクセスできる場合があるため、その権限を悪用される点がSSRFの大きなリスクです。

《 想定される被害・影響》

  • 内部システムや内部APIへアクセスされる

  • サーバー内部の情報や機密情報を取得される

  • クラウド環境の認証情報などを取得される

  • 内部ネットワークの構成や利用中のサービスを調査される

  • Webサーバーを経由して他のシステムへ不正な通信を行われる

  • 接続先によってはデータの変更や重要な処理を実行される

《 対応方法 》

通信先を利用者に自由に指定させない【必須】
通信先があらかじめ決まっている機能では、利用者からURL全体を受け取らず、サーバー側で通信先を決定します。

例えば、

利用者から
https://example.jp/api/...
をそのまま受け取る

のではなく、

service=A
        ↓
サーバー側で
https://api.example.jp/
へ変換

するなど、利用者が通信先を自由に変更できない設計を優先します。

許可する通信先を限定する【必須】
利用者からURLやホスト名を受け取る必要がある場合は、通信を許可するドメイン、IPアドレス、通信方式などを明示的に制限します。

https://api.example.jp   → 許可
https://files.example.jp → 許可
その他                   → 拒否

可能な場合は「危険な接続先を除外する」方式ではなく、「必要な接続先だけを許可する」方式にしてください。

内部ネットワークなどへの通信を防止する【必須】
外部URLへのアクセスを許可する必要がある場合でも、localhost、プライベートIPアドレス、リンクローカルアドレス、クラウド環境のメタデータサービスなど、本来アクセスする必要のない接続先への通信を拒否します。

URLの文字列だけで判断せず、ドメイン名から取得されるIPアドレスについても確認する必要があります。

リダイレクト先も信用しない【必須】
最初に指定されたURLが安全でも、

許可されたURL
    ↓ リダイレクト
内部システム

のように別の接続先へ転送される可能性があります。

外部URLを取得する機能では自動リダイレクトを無効にするか、リダイレクト後の接続先についても同じ検証を行ってください。

サーバーからの通信先をネットワーク側でも制限する【推奨】
Webアプリケーションから任意の内部システムへ通信できないよう、ファイアウォールなどで必要な通信先だけに制限します。アプリケーション側の検証だけに依存せず、万一SSRFが発生した場合でもアクセスできる範囲を限定してください。

オープンリダイレクト
利用者のブラウザを攻撃者のサイトへ飛ばす問題

SSRF
Webアプリのサーバー自身に、内部システムや任意のURLへアクセスさせる問題

※似ているけど異なる

💀 安全でないデシリアライズ

外部から受け取ったデータを、そのままプログラム内部のオブジェクトとして復元することで、不正なデータの生成や処理の実行、場合によっては任意のコード実行につながる脆弱性です。

《 リスク概要 》

デシリアライズとは、保存や通信のために変換されたデータを、プログラムで扱えるオブジェクトなどへ復元する処理です。

オブジェクト
    ↓ シリアライズ
保存・通信できるデータ
    ↓ デシリアライズ
オブジェクトへ復元

このとき、利用者が変更できるデータを安全性の確認なしにデシリアライズすると、攻撃者が細工したデータによって、本来作成されるはずのないオブジェクトや状態を生成される可能性があります。

特に、Javaや.NETなどが持つオブジェクトを直接復元する仕組みでは、使用するクラスやライブラリによって、デシリアライズしただけで予期しない処理が実行され、深刻な場合はサーバー上でコードを実行されることがあります。

なお、JSONなどのデータを単純に読み取ること自体が、この脆弱性というわけではありません。外部データから任意のクラスやオブジェクトを復元するような仕組みを使用する場合に、特に注意が必要です。

《 想定される被害・影響》

  • サーバー上で不正なコードを実行される

  • オブジェクトの値や状態を不正に変更される

  • 本来実行できない処理を実行される

  • 認証や権限などの情報を改ざんされる

  • サーバーのファイルや機密情報へアクセスされる

  • 大量の処理を発生させ、サービスを停止させられる

《 対応方法 》

外部から受け取ったデータをそのままオブジェクトとして復元しない【必須】
利用者から受け取ったデータに対して、言語やフレームワークが提供する任意のオブジェクトを復元できるデシリアライズ機能を、そのまま使用しないようにします。外部とのデータ交換では、必要な項目だけをJSONなどの単純なデータ形式で受け取り、サーバー側で必要なデータ型や項目へ変換する設計を優先してください。

受け取る項目・型・値を限定する【必須】
外部から受け取ったデータについて、

・項目名
・文字列、数値などのデータ型
・文字数や数値範囲
・許可する値

などをサーバー側で確認し、想定していないデータを受け入れないようにします。

例えば、

{
  "name": "user01",
  "age": 30
}

を受け取るAPIであれば、name と age など必要な項目だけを受け取り、外部から任意のクラス名やオブジェクトの種類を指定できるようにしないでください。

やむを得ずデシリアライズ機能を利用する場合は復元できる型を限定する【必須】
既存システムなどでオブジェクトのデシリアライズが必要な場合は、任意のクラスを復元できる状態にせず、利用を許可するクラスや型を明示的に限定します。また、使用している言語やフレームワークが提供する安全なデシリアライズ機能や制限機能を利用してください。

デシリアライズ関連のライブラリを最新のサポート対象バージョンに保つ【必須】
デシリアライズ処理では、特定のクラスやライブラリの組み合わせが攻撃に利用される場合があります。使用しているフレームワークや関連ライブラリの脆弱性情報を確認し、必要なセキュリティ更新を適用してください。→既知の脆弱性を含むソフトウェア・依存パッケージ


💀 サーバーサイドテンプレートインジェクション(SSTI)

利用者から受け取った値をサーバー側のテンプレートへ不適切に組み込むことで、テンプレートの命令として解釈され、情報の取得や不正な処理、場合によってはサーバー上でコードを実行される脆弱性です。

《 リスク概要 》

Webアプリケーションでは、HTMLやメールなどを生成するためにテンプレートエンジンを利用することがあります。

例えば、

こんにちは {{ name }} さん

というテンプレートへ、

name = user01

を値として渡す使い方は一般的です。

一方、利用者から受け取った文字列そのものをテンプレートとして組み立てたり実行したりすると、

利用者の入力
    ↓
テンプレートの一部として解釈
    ↓
テンプレート内の式や機能が実行される

という状態になり、SSTIが発生する可能性があります。

使用しているテンプレートエンジンによって影響は異なりますが、重大な場合はサーバー上で任意のコードを実行されることがあります。

《 想定される被害・影響》

  • サーバー内部の情報を取得される

  • 設定値や機密情報を読み取られる

  • ファイルを読み書きされる

  • 本来実行できない処理を実行される

  • サーバー上で任意のコードを実行される

  • Webアプリケーションやサーバーを乗っ取られる

《 対応方法 》

利用者入力をテンプレートそのものとして実行しない【必須】
利用者から受け取った文字列を連結してテンプレートを作成したり、その文字列をテンプレートとして評価したりしないようにします。

利用者入力は、あくまでテンプレートへ渡す「値」として扱います。

固定されたテンプレート
        +
利用者入力は値として渡す

という設計を基本としてください。

テンプレートの構造を利用者に変更させない【必須】
テンプレート内の式、関数、クラス名などを利用者が自由に指定できる仕組みは避けます。メール本文や帳票などを利用者がカスタマイズできる機能を提供する場合も、利用できる機能や記法を必要な範囲に限定してください。

テンプレートエンジンの安全な機能を利用する【推奨】
利用しているテンプレートエンジンが、利用可能な機能やオブジェクトへのアクセスを制限する仕組みを提供している場合は活用します。ただし、このような制限だけに依存せず、利用者入力をテンプレートとして実行しない設計を優先してください。

テンプレートエンジンや関連ライブラリを適切に更新する【必須】
使用しているテンプレートエンジンや関連ライブラリの脆弱性情報を確認し、サポート対象のバージョンと必要なセキュリティ更新を利用してください。→既知の脆弱性を含むソフトウェア・依存パッケージ


【ログイン・認証・権限管理】


🔒 アカウント情報の推測(ユーザー列挙)

ログイン、ユーザー登録、パスワード再設定などの応答から、アカウントの存在や状態を推測される脆弱性です。

《 リスク概要 》

ログイン、ユーザー登録、パスワード再設定などで、入力したユーザーIDやメールアドレスの登録有無、アカウント状態によって異なるメッセージや応答を返すと、攻撃者に有効なアカウントを特定される可能性があります。

《 想定される被害・影響》

特定されたアカウント情報が、パスワードスプレーやクレデンシャルスタッフィング、フィッシングなどの攻撃に利用され、不正ログインや情報漏えいにつながる可能性があります。

《 対応方法 》

認証・登録・パスワード再設定などでは、アカウントの存在や状態を外部から判別できないメッセージ・応答とします。

例:「入力された情報を確認してください。」

また、メッセージだけでなく、HTTPレスポンスや処理時間などの違いからアカウントの存在を容易に判別できないようにします。

※ 不正ログインへの追加対策として、重要なシステムでは多要素認証(MFA)の導入を行う検討も必要です。


🔒 ログイン認証へのパスワード攻撃

ログイン試行の制御が不足することで、パスワードの推測や漏えい済み認証情報による不正ログインを許す脆弱性です。

《 リスク概要 》

ログイン機能に試行回数の制限、試行間隔の制御、不審なアクセスの検知などが実装されていない場合、攻撃者によって大量のログイン試行を繰り返され、利用者のアカウントへ不正にログインされる可能性があります。

《 代表的な攻撃方法 》

  • 総当たり攻撃(ブルートフォース攻撃)
    特定のアカウントに対して、考えられる多数のパスワードを順番に試す攻撃です。

  • パスワードスプレー攻撃
    多数のアカウントに対して、「password」「123456」など、利用されやすい少数のパスワードを試す攻撃です。アカウントごとの試行回数を抑えながら攻撃するため、単純なアカウントロックを回避される場合があります。

  • クレデンシャルスタッフィング攻撃
    他のWebサービスなどから漏えいしたユーザーID・メールアドレスとパスワードの組み合わせを利用し、同じ認証情報を使い回しているアカウントへのログインを試みる攻撃です。

※これらの攻撃は、複数のIPアドレスや端末を利用して分散して実行されることがあります。そのため、同一IPアドレスからの試行回数だけを制限しても、十分に防止できない可能性があります。

《 想定される被害・影響》

  • アカウントを乗っ取られ、個人情報や機密情報を閲覧・窃取される

  • 利用者になりすまして、登録情報の変更、購入、送金などの不正操作を行われる

  • 管理者アカウントが侵害され、システム全体の情報漏えいや改ざんにつながる

  • 大量のログイン試行により、認証機能の遅延やサービス停止が発生する

《 対応方法 》

ログイン試行を制限する【必須】
アカウントやIPアドレスなどを基準に、一定時間内のログイン試行回数を制限します。ログイン失敗が続いた場合は、一定時間ログインを停止する、または試行間隔を段階的に長くしてください。

制限は、アカウントやIPアドレスなどを組み合わせて実施し、同一アカウントへの大量試行や、多数のアカウントへの少数回ずつの試行を防止してください。

補足
アカウントロックを採用する場合、無期限のロックは、第三者による意図的なログイン失敗によって正規利用者をログインできなくする攻撃に悪用される可能性があります。システムの要件に応じて、一定時間後の自動解除などを検討してください。


🔒パスワード強度の不足

推測されやすいパスワードや、既に漏えいしているパスワードを利用できることで、不正ログインされる脆弱性です。

《 リスク概要 》

短いパスワード、単純な文字列、ユーザーIDを含むパスワードなどを設定できる場合、攻撃者にパスワードを推測され、アカウントへ不正にログインされる可能性があります。

《 想定される被害・影響》

  • アカウントを乗っ取られ、個人情報や機密情報を閲覧・窃取される

  • 利用者になりすまして、登録情報の変更や不正な取引・操作を行われる

  • 管理者アカウントが侵害され、システム内の情報漏えいやデータ改ざんにつながる

《 対応方法 》

安全性の低いパスワードを設定できないようにする【推奨】
パスワードの新規設定や変更時に、次の条件を満たしていることを確認し、条件を満たさないパスワードは設定できないようにします。

設定基準例
・パスワードのみで認証する場合は、15文字以上とする
・多要素認証を必須としている場合は、8文字以上とする
・64文字以上の長いパスワードやパスフレーズを設定できるようにする
・英大文字、英小文字、数字、記号などの文字種の組み合わせを強制しない
・ユーザーID、サービス名、一般的な単語など、推測されやすいパスワードを拒否する
・一般的によく使用されるパスワードや、漏えいが確認されているパスワードを拒否する

《 パスワードの定期変更について 》

パスワードの定期変更は、末尾の数字だけを変えるなど、かえって弱いパスワードの利用を招くため推奨されません。漏えいや不正利用が疑われる場合にのみ、変更を求めてください。


🔒機密情報・認証情報の不適切な保存

パスワードや個人情報などの機密情報を、平文または安全性が不十分な形式で保存することで、情報漏えい時に内容を取得・悪用される脆弱性です。

《 リスク概要 》

パスワード、暗証番号、クレジットカード情報、マイナンバーなどの機密情報を平文で保存している場合、データベース、バックアップ、ログなどが漏えいした際に、その内容をそのまま取得される可能性があります。

また、システム管理者や開発・運用担当者など、内部関係者が必要以上に機密情報を閲覧できる状態も、情報の不正利用や持ち出しにつながるリスクがあります。

パスワードは平文や復号可能な暗号化で保存せず、元に戻せないパスワード保存用の方式でハッシュ化して保存します。ログイン時は、入力されたパスワードを同じ方式でハッシュ化し、保存済みの値と照合します。

《 想定される被害・影響》

  • パスワードや暗証番号を取得され、利用者のアカウントへ不正にログインされる

  • 氏名、住所、連絡先、マイナンバーなどの個人情報が漏えいし、不正利用や詐欺に利用される

  • クレジットカード情報を不正決済などに悪用される

  • 内部関係者によって機密情報を不正に閲覧・持ち出される

  • 情報漏えいへの調査、利用者への通知や補償などが必要となり、企業やサービスの信用が失われる

《 対応方法 》

機密情報を適切な方法で保存する【必須】
機密情報は必要なものだけを保存し、情報の種類に応じて、次の対策を実施します。

情報ごとの対応例
・パスワードは、平文や復号可能な暗号化では保存せず、Argon2idなどのパスワード保存用の方式でハッシュ化する
・個人情報やマイナンバーなど、後から元の値を利用する情報は暗号化して保存し、復号鍵をデータとは分離して安全に管理する
・クレジットカード情報は可能な限り自システムで保存せず、決済代行サービスなどを利用する
・カードのセキュリティコードは、国際的なカードセキュリティ基準により保存禁止されているため、決済承認後に保存しない
・パスワードや機密情報をログへ出力しない。リクエスト・レスポンス内容を記録する場合は、パスワードや機密情報を除外またはマスキングする。
・機密情報を閲覧できる利用者や管理者を、業務上必要な範囲に制限する
・不要になった機密情報は速やかに削除する

《 パスワードの暗号方式》

パスワードは、平文で保存されていれば、漏えいした時点でそのまま取得されます。また、MD5やSHA-1、SHA-256などの高速なハッシュ関数を単独で使用している場合、攻撃者が大量のパスワード候補を短時間で試せるため、元のパスワードを解析される危険性が高くなります。

Argon2idのようなメモリハード型のパスワードハッシュ方式は、1回の計算に一定の処理時間とメモリを必要とさせます。これにより、ハッシュ値が漏えいした場合でも、大量のパスワード候補を試すための時間と費用を増加させ、解析を困難にすることが可能です。


🔒クライアント側への不適切な保存

個人情報、認証情報、業務データなどをブラウザや端末内へ不適切に保存することで、共用端末の利用、端末の紛失、XSSなどにより情報を取得される脆弱性です。

《 リスク概要 》

入力内容の一時保存や、前回の画面状態を復元する機能などで、画面上のデータをlocalStorage、sessionStorage、IndexedDB、Cookieなどへ保存すると、ブラウザ内に情報が残る可能性があります。

特に、画面全体の入力内容やレスポンスデータをまとめて保存する実装では、パスワード、個人情報、決済情報、社内情報など、保存する必要のない機密情報まで含まれる恐れがあります。

ブラウザへ保存された情報は、同じ端末を利用する別の利用者に閲覧されたり、クロスサイトスクリプティング(XSS)によって読み取られたりする可能性があります。

《 想定される被害・影響》

  • 共用端末や紛失した端末から、入力途中の個人情報や業務情報を閲覧される

  • XSSによって、ブラウザに保存された機密情報を窃取される

  • ログアウト後も情報が残り、別の利用者に前回の入力内容や表示内容を閲覧される

  • パスワード、決済情報、マイナンバーなど、本来保存すべきでない情報が意図せず保存される

《 対応方法 》

機密情報をブラウザへ保存しない【必須】
画面の入力内容や状態を保存する場合は、保存対象を項目単位で明確に定義し、パスワード、個人情報、決済情報などの機密情報を含めないようにします。

画面全体の入力値、フォームデータ、APIレスポンスなどを、そのままlocalStorageやIndexedDBへ保存しないようにします。

保存が必要な情報はバックエンド側で管理する【推奨】
入力途中のデータや画面状態などを保存する必要がある場合は、ブラウザへ保存せず、認証・認可されたバックエンド側で管理します。

補足
ブラウザへ保存するデータを暗号化しても、復号処理や鍵を同じWebアプリケーション内で扱う場合、XSSによって復号後の情報を読み取られる可能性があります。機密情報はブラウザへ暗号化して保存するのではなく、認証・認可されたバックエンド側のデータベースなどで管理し、原則としてブラウザ内に残さない設計としてください。


🔒 パスワード再設定・アカウント復旧の不備

本人確認や再設定用トークンの管理が不十分なことで、第三者にパスワードを変更され、アカウントを乗っ取られる脆弱性です。

《 リスク概要 》

パスワード再設定やアカウント復旧は、通常のログインを行わずにアカウントへ再びアクセスするための機能です。

本人確認が不十分であったり、再設定用トークンが推測可能、長期間有効、複数回利用可能であったりすると、第三者にパスワードを変更される可能性があります。パスワード再設定機能は通常の認証を迂回するため、ログイン機能と同等以上の安全性が必要です。

《 想定される被害・影響》

  • 第三者にパスワードを変更され、アカウントを乗っ取られる

  • 個人情報や機密情報を閲覧・窃取される

  • 利用者になりすまして、不正な取引やデータ変更を行われる

  • 登録メールアドレスや多要素認証の設定を変更され、正規利用者がアカウントを取り戻せなくなる

  • 再設定要求を大量に送信され、利用者へ迷惑メールが繰り返し送信される

《 対応方法 》

安全な再設定用トークンを使用する【必須】
再設定用トークンは十分に推測困難な値とし、利用者ごとに発行します。トークンには適切な有効期限を設定し、一度使用された場合や新しいトークンが発行された場合は、以前のトークンを無効化します。

登録済みの連絡先を使用して本人確認する【必須】
再設定用のURLや確認コードは、あらかじめ登録・確認済みのメールアドレスや電話番号などへ送信します。氏名、生年月日、秘密の質問など、第三者が調査・推測できる情報だけで本人確認しないようにしてください。

アカウントの存在を判別できないようにする【必須】
入力されたメールアドレスやユーザーIDが登録されているかどうかにかかわらず、同じメッセージを表示します。

例:「ご入力いただいたメールアドレス宛に、パスワード再設定のご案内を送信しました。」

レスポンス内容や処理時間の違いからも、アカウントの存在を容易に判別できないようにします。→アカウント情報の推測(ユーザー列挙)

再設定要求の回数を制限する【必須】
同一アカウントやIPアドレスから短時間に大量の再設定要求が行われないよう、送信回数や試行回数を制限します。

再設定後に利用者へ通知する【推奨】
パスワードの変更やアカウント復旧が行われた場合は、登録済みの連絡先へ通知し、利用者が不正な変更を早期に把握できるようにします。

補足
再設定用トークンや確認コードを、ログへ平文で出力してはいけません。また、パスワード再設定だけで多要素認証を解除できる設計は、認証全体の安全性を低下させるため注意が必要です。


🔒 多要素認証(MFA)の未導入・実装不備

パスワードなど一つの認証要素だけに依存することや、MFAの処理を回避できることにより、不正ログインされる脆弱性です。

《 リスク概要 》

パスワードだけで認証している場合、パスワードが推測・漏えいすると、それだけで不正ログインされる可能性があります。

多要素認証を導入することで、パスワードが第三者に知られた場合でも、不正ログインの可能性を低減できます。

《 想定される被害・影響》

  • 漏えい・推測されたパスワードを利用して、アカウントへ不正にログインされる

  • 個人情報や機密情報を閲覧・窃取される

  • 利用者になりすまして、不正な取引やデータ変更を行われる

  • 管理者アカウントが侵害され、システム全体の情報漏えいや改ざんにつながる

《 対応方法 》

重要なアカウントやシステムにMFAを導入する【推奨】
管理者アカウントや、個人情報・決済情報などを扱う重要なシステムでは、パスワードに加えて別の認証要素を要求します。

重要なシステムでは、SMSやメールで送る確認コードだけに依存せず、端末の指紋認証・顔認証・PINなどを利用するパスキーを導入します。

パスキー
パスワードの代わりに指紋・顔認証や画面ロック(PIN)を使って、Webサイトやアプリに安全かつ簡単にログインできる認証技術。登録した正規のWebサイトでのみ認証が行われるため、偽サイトへ誘導されても認証情報を盗まれにくい特徴がある。

MFAをすべての認証経路で強制する【必須】
MFAを有効にしているアカウントでは、Web画面、API、モバイルアプリ、外部認証など、すべてのログイン経路で追加認証を要求するように実装してください。

MFAの確認コードを適切に管理する【必須】
確認コードは推測困難な値とし、短い有効期限と試行回数の制限を設定します。一度使用したコードは直ちに無効化し、再利用できないようにします。

MFAの変更・解除・復旧を保護する【必須】
MFAの登録、変更、解除、復旧を行う場合は、現在の認証要素による再認証など、十分な本人確認を行います。

補足
MFAは不正ログインの可能性を大きく低減しますが、すべての攻撃を防止するものではありません。特に、偽サイトへ確認コードを入力させるフィッシング攻撃への対策として、可能な場合はパスキーなどのフィッシング耐性のある方式を利用してください。


🔒 認証・認可チェックの不備

未ログインの利用者や権限のない利用者に、本来利用できない画面・機能・データを閲覧・操作される脆弱性です。

《 リスク概要 》

画面を非表示にしたり、メニューやボタンを表示しないようにしていても、URLの直接入力やリクエストの改ざんによって、サーバへ直接アクセスすることができます。そのため、サーバ側で「ログインしているか」「そのユーザーに対象の画面・機能・データを利用する権限があるか」を確認していない場合、本来許可されていない処理を実行される可能性があります。

また、JavaScript、画像、PDF、ダウンロードファイルなどについても、機密情報を含む場合は直接URLへアクセスされることを前提に、権限を確認する必要があります。

《 想定される被害・影響》

  • 未ログインの利用者に、ログイン後の画面や機能を利用される

  • 一般ユーザーに、管理者向けの画面や機能を不正に利用される

  • 本来閲覧できない個人情報や機密情報を取得される

  • 権限のないデータを登録・変更・削除される

  • 機密性のあるファイルやリソースを直接取得される

《 対応方法 》

サーバ側でリクエスト単位に認証・権限チェックを行う【必須】
ログインが必要な画面・API・機能では、リクエストを受けるたびに、ログイン済みであることと、その利用者に処理を実行する権限があることをサーバ側で確認します。画面上でメニューやボタンを非表示にしていても、URLの直接入力やリクエストの改ざん、APIの直接呼び出しによって処理を要求できます。そのため、画面側の制御に依存せず、すべてのリクエストでサーバ側の認証・権限チェックを行ってください。

権限のチェック例
・ログイン済みであること
・管理者、一般ユーザーなど、対象の画面や機能を利用できる権限・ロールであること
・対象データが本人またはアクセスを許可された組織のものであること
・閲覧、登録、変更、削除などの操作・実行権限があること
・管理者向けURLやAPIを一般ユーザーが直接実行できないこと
・機密性のあるファイルやリソースにもアクセス権限が設定されていること

フロントエンドの表示制御を権限チェックとして使用しない【必須】
ボタンの非表示、入力項目の非活性、JavaScriptによる画面制御などは、利用者が変更・回避できます。フロントエンドの制御は画面上の利便性を向上させるためのものとし、実際のアクセス可否は必ずサーバ側で判定してください。→Hiddenフィールドマニピュレーション

補足
公開して問題のないJavaScriptや画像などは、認証・認可を行う必要はありません。個人情報、社内資料、帳票、添付ファイルなど、利用者によって閲覧可否が異なるリソースについては、直接URLへアクセスされた場合でもサーバ側で権限を確認してください。


🔒 IDOR/BOLA

リクエストに含まれるIDなどを変更することで、本来アクセスできない他の利用者や組織のデータを閲覧・変更される脆弱性です。

IDOR(Insecure Direct Object Reference)
「安全でない直接オブジェクト参照」という意味。
URLやリクエスト中の userId=100、orderId=500 などを書き換えることで、他人のデータへアクセスできてしまう問題を指す。

BOLA(Broken Object Level Authorization)
「オブジェクト単位の認可不備」という意味。
主にAPIで使われる表現で、APIに指定されたユーザー、注文、ファイルなどの対象データごとにアクセス権限を確認していない問題を指す。

【簡単な説明】

URLやAPIに含まれるユーザーID、注文ID、ファイルIDなどを書き換えることで、他の利用者や組織のデータへ不正にアクセスされる脆弱性です。

《 リスク概要 》

WebアプリケーションやAPIでは、URLやリクエストパラメータに、対象データを特定するためのIDを指定することがあります。

例えば、自分の注文を表示するURLが次の場合、

/orders/1001

1001 を 1002 に変更した際に、別の利用者の注文を表示できてしまうと脆弱性となります。

問題はIDを変更できること自体ではなく、サーバ側で「ログイン中の利用者が、そのデータへアクセスしてよいか」を確認していないことです。利用者から受け取ったIDを使ってデータへアクセスする場合は、対象オブジェクトごとに認可チェックを行う必要があるとしています。

《 想定される被害・影響》

  • 他の利用者の個人情報や注文情報などを不正に閲覧される

  • 他の利用者のデータを変更・削除される

  • 他社・他部署など、本来アクセスできない組織の情報を取得される

  • 他の利用者が所有するファイルや帳票を不正にダウンロードされる

  • 管理対象のIDを変更され、権限のないデータに対して処理を実行される

《 対応方法 》

リクエスト単位で対象データへのアクセス権限を確認する【必須】
URL、リクエストパラメータ、JSONなどからIDを受け取る場合は、IDが存在することだけを確認するのではなく、ログイン中の利用者がそのデータを閲覧・変更・削除してよいことを、サーバ側で毎回確認します。リクエストで送られてくる全ての項目・データについて、ログイン中の利用者がそのデータへアクセスする権限を持っているかを、リクエストごとにサーバ側で確認する必要があります。

確認例
・対象項目・データがログイン中の利用者本人のものであること
・対象項目・データが利用者の所属する会社・組織のものであること
・その利用者に閲覧、変更、削除などの操作権限があること

クライアントから受け取ったIDを信用しない【必須】
画面上で選択できるIDだけが送信されるとは限りません。Hiddenフィールド、URL、JavaScript、APIリクエストなどの値は利用者が変更できるため、サーバ側でアクセス可能なデータかを必ず確認します。→Hiddenフィールドマニピュレーション

補足
連番のIDをUUIDなど推測しにくい値へ変更すると攻撃されにくくなる場合はありますが、それだけでは対策になりません。IDを推測できるかどうかに関係なく、サーバ側でアクセス権限を確認する必要があります。


🔒 Mass Assignment(意図しない項目の更新)

開発者が送信されることを想定していない項目までリクエストに追加され、その値がそのままデータへ反映されることで、本来変更できない情報を不正に変更される脆弱性です。

《 リスク概要 》

WebアプリケーションやAPIでは、フォームやJSONで受け取った内容を、ユーザー情報などのデータへ反映する処理があります。開発者は、画面に表示している項目だけが送信されると考えてしまうことがありますが、攻撃者はリクエストを直接変更して、画面に存在しない項目を追加できます。

例えば、通常は名前だけを変更する機能に対して、

{
  "name": "user01",
  "isAdmin": true
}

のように isAdmin を追加し、その値まで更新できてしまうと問題になります。つまり、「そのデータを変更してよいか」だけでなく、「どの項目まで変更してよいか」もサーバ側で制御する必要があります。

例えば、自分のプロフィールを変更できる利用者でも、氏名やメールアドレスは変更できる一方で、管理者権限、所属会社、ユーザーIDなどまで自由に変更できてはいけません。

《 想定される被害・影響》

  • 一般ユーザーが管理者権限を取得する

  • 所属会社やユーザーIDなどを不正に変更される

  • 金額、ステータス、承認状態などを改ざんされる

  • 本来変更できない内部管理項目を書き換えられる

  • アプリケーションの処理や権限を不正に変更される

《 対応方法 》

更新を許可する項目をサーバ側で明示する【必須】
リクエストで送信されたすべての項目をそのままデータへ反映せず、利用者が変更してよい項目だけをサーバ側で指定します。

例えば、プロフィール変更で name と email だけを変更できる場合は、その2項目だけを取り出して更新します。

const { name, email } = req.body;

await updateUser({
  name,
  email
});

isAdmin、role、userId、companyId など、利用者が変更してはいけない項目は、リクエストに含まれていても更新対象にしません。

リクエスト内容をデータへそのまま一括反映しない【必須】
フォームやJSONの内容を、データベースのモデルや内部オブジェクトへ丸ごと反映する実装は避けます。フレームワークの自動バインド機能を利用する場合も、更新を許可する項目を明示的に制限してください。

用途ごとに受け取るデータを分ける【推奨】
登録、一般ユーザーによる更新、管理者による更新などで同じDTO(Data Transfer Object)を共通利用すると、本来受け付ける必要のない項目まで含まれやすくなります。そのDTOをそのままDAO(Data Access Object)へ渡して一括更新すると、想定していない項目までデータベースへ反映される可能性があります。そのため、外部から受け取るDTOは用途ごとに必要な項目だけを定義し、DAOへ渡す前にも更新対象を明確にしてください。

DTO(Data Transfer Object)
画面やAPIなどとの間で受け渡すデータをまとめるためのオブジェクト

DAO(Data Access Object)
データベースへの登録・更新・検索などの処理をまとめるための仕組み


🔒 業務フロー・状態遷移の回避

申請、承認、決済、本人確認など、本来必要な手順や順序を飛ばして処理を実行できてしまう脆弱性です。

《 リスク概要 》

Webアプリケーションでは、複数の処理を決められた順序で実行する業務があります。

例えば、

申請 → 承認 → 決済 → 完了

という処理で、本来は「承認済み」の場合だけ決済できるにもかかわらず、決済用のURLやAPIを直接呼び出すことで、

申請 → 決済

と処理を進められてしまうと問題になります。

画面上では前の処理が完了しないと次へ進めないようにしていても、攻撃者はURLやAPIを直接呼び出せます。そのため、現在の状態でその処理を実行してよいかを、サーバ側で確認する必要があります。

《 想定される被害・影響》

  • 承認前の申請を確定される

  • 本人確認を行わず重要な処理を実行される

  • 決済や契約などの必要な手順を飛ばされる

  • 完了済みの処理を再度実行される

  • キャンセル済み・無効状態のデータを不正に処理される

  • 本来成立しない業務状態やデータが作成される

《 対応方法 》

処理を実行するたびに現在の状態をサーバ側で確認する【必須】
画面上の遷移だけを信用せず、リクエストごとに対象データの現在の状態を確認し、その状態から実行してよい処理だけを許可します。

例えば、決済処理では「承認済み」であること、承認処理では「申請中」であることなどを確認します。

申請中   → 承認     :許可
承認済み → 決済     :許可
申請中   → 決済     :拒否
取消済み → 決済     :拒否

画面遷移やフロントエンドの状態を信用しない【必須】
「前の画面を通過したから処理済み」と判断せず、データベースなどサーバ側で管理している状態を確認します。Hidden項目やJavaScriptの値、URLパラメータなどで status=approved のような状態を送信させ、その値だけを信用して処理を進めないようにしてください。

同じ処理を不正に繰り返せないようにする【必要に応じて】
決済、ポイント付与、クーポン利用、申請確定など、1回だけ実行すべき処理については、すでに実行済みでないことをサーバ側で確認します。二重送信やAPIの再実行によって、同じ処理が複数回成立しないようにしてください。→二重実行・競合処理の不備


🔒 二重実行・競合処理の不備

同じ処理の再送や複数のリクエストの同時実行によって、本来1回だけ行う処理が複数回実行され、二重決済や在庫超過などが発生する脆弱性です。

《 リスク概要 》

Webアプリケーションでは、ボタンの連打、画面の再読み込み、通信エラーによる再送、APIの直接呼び出しなどによって、同じ処理が複数回リクエストされることがあります。例えば、決済処理が2回送信されると、同じ注文に対して二重に決済される可能性があります。

また、複数のリクエストがほぼ同時に実行されると、それぞれが処理前の同じ状態を確認し、両方とも処理を実行してしまう場合があります。

例えば、在庫が残り1個の場合でも、

リクエストA → 在庫1個を確認 → 購入可能
リクエストB → 在庫1個を確認 → 購入可能
                         ↓
                 両方とも購入処理

となると、本来1個しかない商品を複数回販売してしまう可能性があります。

《 想定される被害・影響》

  • 同じ注文や決済が複数回実行される

  • 在庫数を超えて商品を購入される

  • ポイントやクーポンを重複して取得・利用される

  • 送金や返金が複数回実行される

  • 同じ申請や登録が複数作成される

  • 「1回だけ利用可能」などの回数制限を回避される

《 対応方法 》

同じ処理の再送を防止する【必須】
決済、申請、登録など、1回だけ実行すべき処理では、同じリクエストが再送されても複数回処理されないようにします。画面上でボタンを押せなくするだけでは、リクエストを直接再送できるため、サーバー側で制御する必要があります。

ワンタイムトークンを利用する【必要に応じて】
確認画面からの登録・申請などでは、一度だけ使用できるトークンを発行し、処理完了後に無効化します。

確認画面
   ↓
ワンタイムトークンを発行
   ↓
登録処理で使用
   ↓
使用済みにする
   ↓
同じトークンの再送 → 拒否

これにより、二重クリック、再読み込み、戻る操作などによる同じ処理の再実行を防ぎます。

一意のリクエストIDを利用して重複実行を防ぐ【必要に応じて】
決済や外部API連携など、通信エラーによる再送が想定される処理では、リクエストごとに一意の識別子(冪等性キー)を付けます。

1回目
リクエストID: abc123
      ↓
処理を実行して結果を記録

同じIDで再送
リクエストID: abc123
      ↓
再実行せず前回の結果を返す

このように、同じリクエストが複数回送られても処理結果を1回分にする仕組みを「冪等性」といいます。OWASPも、決済や送金などの外部処理では冪等性キーを使用して再送による重複実行を防ぐことを推奨しています。

同時実行による競合を防ぐ【必須】
在庫、残高、ポイント、利用回数などを更新する処理では、複数のリクエストが同時に実行されても、本来の制限を超えて処理が成立しないようにします。画面表示時の状態だけを信用せず、実際に処理を確定する時点で最新の状態を確認し、安全に更新できるように設計してください。

利用回数や現在の状態を処理時に確認する【必須】
「1回だけ利用可能」「残高以内」「在庫あり」「未処理」などの条件は、画面を表示した時点だけでなく、実際に処理を確定する時点でもサーバー側で確認します。同時に複数のリクエストが届いても、本来の制限を超えて処理が成立しないようにしてください。


🔒JWT・アクセストークンの検証不備

ログイン後に利用するJWTやアクセストークンを正しく確認しないことで、不正なトークンを受け入れ、なりすましや不正なAPI操作につながる脆弱性です。

《 リスク概要 》

WebアプリケーションやAPIでは、ログインに成功すると、サーバーからアクセストークンと呼ばれる認証用の情報が発行されることがあります。

利用者は、その後APIを呼び出すたびにアクセストークンを送信し、サーバーはトークンを確認して「誰がログインしているか」「その処理を実行してよいか」を判断します。

(1) ID・パスワードなどでログイン
        ↓
(2) サーバーがアクセストークンを発行
        ↓
(3) APIを呼ぶたびにトークンを送信
        ↓
(4) サーバーがトークンを検証
        ↓
(5) 問題がなければ処理を実行

JWT(JSON Web Token)は、アクセストークンなどに利用される代表的な形式の一つです。

JWTには、利用者を識別する情報、有効期限、発行者、利用先、権限などを含めることができ、電子署名によって内容が不正に変更されていないことを確認できます。ただし、署名が正しいだけで、そのトークンを使用してよいとは限りません。

期限切れではないか、信頼する認証サーバーが発行したものか、自分のシステム向けか、必要な権限を持っているかなども確認する必要があります。これらの検証が不足すると、本来使用できないトークンを受け入れてしまう可能性があります。

《 想定される被害・影響》

  • 偽造・改ざんされたトークンを使用される

  • 有効期限が切れたトークンを使用される

  • 別のシステム向けに発行されたトークンを使用される

  • 信頼していない発行元のトークンを受け入れる

  • 権限のないAPIや機能を利用される

  • 他の利用者になりすましてデータを閲覧・変更される

《 対応方法 》

JWTをリクエストごとに検証する【必須】
JWTを受け取った場合は、単に内容を読み取るだけではなく、署名や有効期限などをサーバー側で確認します。

署名アルゴリズムをサーバー側で限定する【必須】
JWTには、どの方法で署名したかを示す alg という情報があります。この値をそのまま信用せず、サーバー側で使用を許可する署名方式をあらかじめ指定します。

許可する例
RS256
ES256

許可していない方式
  ↓
拒否

署名なしを示す alg: none や、想定していない署名方式を受け入れないようにします。

JWTライブラリの検証機能を使用する【必須】
JWTの署名確認などを独自に実装せず、十分に利用実績があり、保守されているJWTライブラリを使用します。
JWTはデコードするだけで内容を読み取れますが、それだけでは正しいトークンとは判断できません。署名、有効期限、発行者、利用先などを検証し、検証に成功したトークンだけを使用してください。

トークンの権限をAPIごとに確認する【必須】
有効なトークンを持っているだけで、すべての処理を許可してはいけません。例えば、

read → 閲覧API:許可
read → 削除API:拒否

admin → 管理API:許可

のように、リクエストごとに、そのトークンが対象APIを利用するために必要な権限を持っていることをサーバー側で確認します。→認証・認可チェックの不備

補足
アクセストークンは必ずJWT形式とは限りません。JWT以外の形式を利用する場合も、採用している認証方式に従って、有効期限、失効状態、権限などを確認してください。


🔒 ログイン履歴・不審な認証の検知不足

ログインの記録や不審な認証の検知が不足していることで、不正ログインが発生しても利用者や管理者が気付かず、被害が継続・拡大する脆弱性です。

《 リスク概要 》

パスワードの漏えいや推測などによって第三者にログインされた場合でも、ログイン履歴が記録・確認できなければ、不正利用に気付くことが困難になります。また、ログイン失敗の急増や、通常とは異なる接続元からのログインなどを監視していないと、総当たり攻撃やクレデンシャルスタッフィングなどの兆候を見逃す可能性があります。

《 想定される被害・影響》

  • 不正ログインに長期間気付かない

  • 個人情報や機密情報を継続的に閲覧される

  • 利用者になりすまして不正な操作を行われる

  • 総当たり攻撃などの認証攻撃を早期に発見できない

  • インシデント発生後に、誰がいつログインしたか調査できない

《 対応方法 》

ログイン成功・失敗を記録する【必須】
ログインの成功・失敗について、日時、ユーザー、接続元など、調査に必要な情報をサーバー側へ記録します。→セキュリティログ・監視の不足

利用者がログイン履歴を確認できるようにする【推奨】
前回ログイン日時や最近のログイン履歴を利用者が確認できるようにし、自分が操作していないログインに気付けるようにします。

利用者への情報表示項目例
・ログイン日時
・利用端末・ブラウザ
・接続地域やIPアドレスなど、必要に応じた接続元情報

不審な認証を検知・通知する【推奨】
短時間の大量ログイン失敗、複数のIPアドレスからの認証失敗、通常とは異なる接続元からのログインなどを監視します。不正アクセスが疑われる場合は、管理者へのアラートや、必要に応じて利用者へのログイン通知を行います。→セキュリティログ・監視の不足

認証情報をログへ記録しない【必須】
パスワード、セッションID、アクセストークンなどの認証情報は、ログイン履歴や監視ログへ記録しないようにします。


🔒 APIの過剰利用・リソース消費

APIの利用回数や処理量に適切な制限がないことで、大量のリクエストや高負荷な処理を実行され、サービス停止や機能の不正利用、外部サービスの利用料金増加などにつながる脆弱性です。

《 リスク概要 》

APIでは、1回のリクエストでもCPU、メモリ、データベース接続、通信量などのリソースを使用します。また、メール・SMS送信、外部API、AIサービスなど、実行するたびに料金が発生する機能もあります。

これらに適切な制限がないと、

大量のAPIリクエスト
        ↓
大量の処理を実行
        ↓
システム負荷・外部サービス利用量が増加

となり、サービス停止や想定外の費用発生につながる可能性があります。

さらに、クーポン発行、予約、メール送信などの業務機能を自動的に大量実行されることで、本来想定していない方法でサービスを悪用される場合もあります。

《 想定される被害・影響》

  • 大量アクセスによるサービス停止や性能低下

  • CPU、メモリ、通信量などの過剰消費

  • 外部API、メール、SMS、AIサービスなどの利用料金増加

  • メール送信や投稿機能などを利用したスパム

  • 予約、申請、クーポンなどの大量取得・大量実行

  • 一部の利用者によるリソースの占有

《 対応方法 》

APIの利用回数を必要に応じて制限する【必須】
大量に実行されると問題になるAPIでは、利用者、アカウント、APIキー、IPアドレスなどを基準として、一定時間内に実行できる回数を制限します。

例えば、

通常の利用       → 許可
短時間の大量実行 → 制限

のように、機能の用途に応じた上限を設定します。

特に、ログイン、メール・SMS送信、外部API呼び出し、AI処理など、繰り返し実行による影響が大きい機能では適切な制限を設けてください。

1回のリクエストで処理できる量を制限する【必須】
大量のデータや極端に重い処理を1回のリクエストで実行できないよう、機能に応じて上限を設定します。

例えば、

・リクエストサイズ
・一度に取得・更新できる件数
・ファイルサイズ
・検索結果件数
・処理時間

などについて、通常の利用に必要な範囲で制限します。

大量実行されると問題になる業務機能を保護する【必須】
予約、申請、クーポン取得、投稿、メール送信などは、単にAPIへログインできるかだけでなく、同じ利用者が短時間に大量実行できないかも確認します。業務上「1人1回」「1日○回まで」などの制限がある場合は、画面側ではなくサーバー側で確認してください。

制限を超えたリクエストを適切に拒否する【推奨】
設定した利用上限を超えた場合は処理を実行せず、APIでは必要に応じて 429 Too Many Requests など適切なレスポンスを返します。また、大量アクセスや異常な利用が継続している場合は、ログを記録し、必要に応じて監視・通知できるようにしてください。


【ブラウザ・Cookie・セッション管理】


🔐 非セキュアクッキー

Cookieのセキュリティ設定が不十分なことで、セッションIDなどを盗まれ、不正に利用される脆弱性です。

《 リスク概要 》

HTTPSで利用しているCookieでも、Secure 属性が設定されていない場合、同じサイトのHTTP URLへアクセスした際にCookieが送信される可能性があります。

特に、HTTPのURLからHTTPSのURLへリダイレクトする構成では、HTTPSへ切り替わる前の通信が暗号化されていないため、利用者の端末からWebサーバまでの通信経路上でセッションIDなどのCookieを盗み見られる恐れがあります。

その結果、盗まれたセッションIDを利用して、利用者になりすまされる可能性があります。

《 想定される被害・影響》

  • セッションIDを盗まれ、利用者になりすましてサービスを利用される

  • 個人情報や機密情報を不正に閲覧される

  • 利用者になりすまして、データの登録・変更・削除などを行われる

《 対応方法 》

セッションCookieに Secure 属性を設定する【必須】
セッションIDなどの重要な情報を保存するCookieには Secure 属性を設定し、HTTPS通信の場合にのみCookieが送信されるようにします。

Set-Cookie: sessionId=xxxxx; Secure

補足
WebサイトをHTTPSで提供している場合でも、Secure 属性は設定してください。HTTPSは通信を暗号化する仕組みであり、Secure 属性はCookieがHTTP通信へ送信されることを防ぐための設定です。

セッションCookieのアクセス・送信範囲を適切に制御する【必須】
セッションIDを保存するCookieに、JavaScriptから読み取れないようにする HttpOnly 属性を設定します。また、システムの仕様に応じて SameSite属性を設定し、Cookieが送信される範囲を制限します。

補足
SameSite 属性は、外部サイトからのアクセス時にCookieを送信する範囲を制御する設定です。通常のWebサイトでは Lax を使用し、外部サイトからのアクセスでもCookieを一切送信する必要がない場合は Strict を使用します。外部の認証・決済サービスなどとの連携で、サイトをまたいでCookieを送信する必要がある場合は SameSite=None; Secure を使用します。

Strict:外部サイトから遷移してきた場合もCookieを送らない。最も厳しいが、外部連携で困りやすい。
Lax:通常のリンク遷移ではCookieを送るが、外部サイトからのPOSTなどでは制限する。一般的なWebサイトでは使いやすい。
None:外部サイトをまたいでもCookieを送る。Secure が必須。


🔐セッション固定(Session Fixation)

攻撃者があらかじめ把握しているセッションIDを利用者に使わせ、その状態でログインさせることで、ログイン後のセッションを乗っ取られる脆弱性です。

《 リスク概要 》

Webアプリケーションでは、ログイン前からセッションIDを発行している場合があります。ログイン成功後も同じセッションIDを使い続けると、攻撃者が事前に把握しているセッションIDを利用者に使わせ、その状態でログインさせることで、攻撃者も同じセッションIDを利用してログイン後の機能へアクセスできる可能性があります。

また、ログイン時だけでなく、ユーザーの権限や認証状態が変わった後も同じセッションIDを使い続けると、同様にセッションを不正利用される恐れがあります。

《 想定される被害・影響》

  • 利用者になりすましてログイン後の機能を利用される

  • 個人情報や機密情報を不正に閲覧される

  • 利用者になりすまして、データの登録・変更・削除などを行われる

  • 管理者など高い権限のセッションを乗っ取られ、管理機能を不正に操作される

《 対応方法 》

認証状態や権限が変わるタイミングでセッションIDを再生成する【必須】
ログイン成功時など、利用者の認証状態や権限が変わった場合は、それまで使用していたセッションIDを無効化し、新しいセッションIDを発行します。

対象例
・ログイン成功時
・パスワード変更後
・ユーザー権限やロールが変更された場合
・一般ユーザーから管理者など、より高い権限へ切り替わる場合

ログアウト時にセッションを破棄する【必須】
ログアウト時は、使用していたセッションをサーバ側で無効化し、それまでのセッションIDを再利用できないようにします。

ログアウト後も匿名ユーザーとしてセッションを継続する場合は、ログイン中に使用していたセッションIDを引き継がず、新しいセッションIDを発行します。


🔐セッションハイジャック

セッションIDや認証トークンを盗まれたり推測されたりすることで、正規の利用者になりすましてログイン後の機能を利用される脆弱性です。

《 リスク概要 》

Webアプリケーションでは、ログイン後の利用者をセッションIDなどの情報で識別し、画面を移動するたびにパスワードを確認することは通常ありません。そのため、セッションIDが通信の盗聴、XSS、推測可能なセッションID、不適切な保存などによって第三者に取得されると、そのセッションIDを使用して利用者になりすまされる可能性があります。

《 想定される被害・影響》

  • 利用者になりすましてログイン後の機能を利用される

  • 個人情報や機密情報を不正に閲覧される

  • 登録情報やデータを不正に変更・削除される

  • 購入、送金、ポイント利用などの不正な操作を行われる

  • 管理者のセッションを奪われた場合、管理機能を不正に操作される

《 対応方法 》

推測困難なセッションIDを使用する【必須】
セッションIDを独自に生成する場合は、連番、日時、ユーザーIDなどから推測できる値を使用せず、暗号学的に安全な乱数等を使用します。可能な限り、使用しているWebフレームワークやセッション管理機能が提供するセッションID生成機能を利用してください。

セッションIDはCookieで管理する【必須】
セッションIDをURLのクエリパラメータなどへ含めてはいけません。URLに含めると、ブラウザの履歴、アクセスログ、Referer(リンク元URL情報)などを経由して漏えいする可能性があります。セッションIDはCookieを利用して管理してください。

セッションCookieのアクセス・送信範囲を適切に制御する【必須】
セッションIDを保存するCookieには、HTTPS通信でのみ送信する Secure 属性と、JavaScriptから読み取れないようにする HttpOnly 属性を設定します。また、システムの仕様に応じて SameSite属性を設定し、Cookieが送信される範囲を制限します。→非セキュアクッキー

HTTPSを使用する【必須】
ログイン画面だけでなく、ログイン後を含むWebアプリケーション全体をHTTPSで通信します。認証後にHTTPへ切り替わる構成にしてはいけません。

セッションに適切な有効期限を設定する【必須】
一定時間操作がない場合や、一定時間以上ログイン状態が継続した場合は、セッションを無効化します。→セッションタイムアウトの不備

ログアウト時にセッションを無効化する【必須】
ログアウト時は、ブラウザ側のCookieを削除するだけでなく、サーバ側のセッションも無効化し、それまで使用していたセッションIDを再利用できないようにします。→セッション固定

認証状態や権限が変わる場合はセッションIDを再生成する【必須】
ログイン成功時や権限変更時などには、それまで使用していたセッションIDを無効化し、新しいセッションIDを発行します。→セッション固定

接続元情報をセッションの検証に利用する【条件付き推奨】
社内システムや管理画面など、利用端末や接続元ネットワークがある程度固定されている場合は、IPアドレスやUser-Agentなどをセッション情報とあわせて確認し、不正利用の検知に利用します。ただし、正規利用者でも通信環境の切り替えやブラウザの更新などによって値が変わることがあります。不一致だけでセッションを無効化すると、正常な操作中に突然ログアウトされ、入力途中の内容が失われるなど、利用者への影響が発生します。


🔐 セッションタイムアウトの不備

セッションの有効期限が適切に設定されていないことで、長時間ログイン状態が維持され、第三者にログイン済みの状態を不正利用される脆弱性です。

《 リスク概要 》

セッションの有効期限が長すぎたり、無期限に設定されていたりすると、利用者がログアウトせずに離席した場合や、セッションIDが第三者に取得された場合に、長時間そのセッションを利用される可能性があります。

また、利用者が操作を続けている限り無期限にセッションが延長される設計では、盗まれたセッションIDも長期間利用される恐れがあります。

《 想定される被害・影響》

  • 離席中の端末を第三者に操作され、利用者になりすまされる

  • 盗まれたセッションIDを長時間利用され、不正アクセスされる

  • 個人情報や機密情報を不正に閲覧される

  • 利用者になりすまして、データの登録・変更・削除などを行われる

  • 管理者のセッションを利用され、管理機能を不正に操作される

《 対応方法 》

セッションに無操作タイムアウトを設定する【必須】
一定時間操作がない場合は、セッションをサーバ側で無効化し、再度ログインを求めます。

設定目安
・個人情報、決済、管理機能などを扱う重要システム:無操作 2~5分程度
・一般的なWebシステム:無操作 15~30分程度

セッションに絶対有効期限を設定する【必須】
操作が継続している場合でも、ログインから一定時間が経過したらセッションを無効化し、再認証を求めます。業務システムなど長時間利用するシステムでは、4~8時間程度を一つの目安とし、システムの利用形態に応じて設定します。

補足
セッションタイムアウトはブラウザ側だけで判定せず、サーバ側で有効期限を管理してください。ブラウザのCookieが残っていても、期限切れのセッションIDではアクセスできない状態にする必要があります。


🔐 クロスサイトリクエストフォージェリ(CSRF)

ログイン中の利用者を悪意のあるサイトへ誘導し、その利用者のブラウザから不正なリクエストを送信させることで、本人の操作として処理される脆弱性です。

《 リスク概要 》

ログイン中の利用者が悪意のあるWebサイトを開くと、そのサイトから別のWebサービスへ不正なリクエストを送信させられる場合があります。ブラウザはログイン中のCookieを自動的に送信するため、Webアプリケーション側で「本当に利用者本人が操作したリクエストか」を確認していないと、本人の操作として処理される可能性があります。

セッションハイジャックとは異なり、攻撃者がセッションIDを盗むのではなく、正規利用者のブラウザを利用して不正な処理を実行させる点が特徴です。

《 想定される被害・影響》

  • 登録情報やメールアドレスなどを不正に変更される

  • パスワードやセキュリティ設定を変更される

  • 商品購入、送金、ポイント利用などの処理を不正に実行される

  • データの登録・変更・削除などを利用者の意思に反して実行される

  • 管理者が攻撃を受けた場合、管理機能を不正に実行される

  • 利用者になりすまして、知り合いへ広告・迷惑メッセージ・不正なリンクなどを送信される

《 対応方法 》

CSRFトークンによるチェックを行う【必須】
サーバ側で推測困難なCSRFトークンを発行し、登録・変更・削除などのリクエストに含めます。サーバ側で正しいトークンであることを確認し、不正なリクエストを拒否します。CSRFトークンはセッションIDとは別の値として生成し、セッション単位またはリクエスト単位で管理します。

使用しているWebフレームワークにCSRF対策機能がある場合は、独自実装せず標準機能を利用してください。

Cookieに SameSite 属性を設定する【推奨】
セッションCookieに SameSite 属性を設定すると、外部サイトからのリクエストにCookieが送信される範囲を制限でき、CSRFのリスクを軽減できます。→非セキュアクッキー


🔐 クリックジャッキング

正規のWeb画面を別のWebサイト上に重ねて表示し、利用者に意図しないボタンやリンクをクリックさせる脆弱性です。

《 リスク概要 》

攻撃者は、正規のWebサイトを <iframe> などで罠サイト上に重ね、透明にしたり位置を調整したりすることで、利用者に別の操作をしているように見せることがあります。

例えば、

画面上では
「プレゼントを受け取る」
    ↓
クリック

実際には
正規サイトの「設定変更」をクリック

のように、利用者が意図していない操作を正規サイト上で実行させられる可能性があります。

《 想定される被害・影響》

  • アカウント設定を変更させられる

  • 投稿、フォロー、共有などを実行させられる

  • 商品購入や申請などを実行させられる

  • 権限変更などの重要な操作を実行させられる

《 対応方法 》

他のWebサイトから画面を埋め込めないようにする【必須】
HTTPレスポンスヘッダーの Content-Security-Policy に frame-ancestors を設定し、自サイトの画面をどこからフレーム表示できるか制限します。

フレーム表示をすべて禁止する場合

Content-Security-Policy: frame-ancestors 'none';

同一オリジンからのみ許可する場合

Content-Security-Policy: frame-ancestors 'self';

特定のWebサイトからのみ許可する場合

Content-Security-Policy: frame-ancestors 'self' https://example.jp;

業務上フレーム表示が不要な画面は、原則として frame-ancestors 'none' などで外部サイトから埋め込めないようにしてください。


🔐 CORS設定の不備

他のWebサイトからAPIやデータへのアクセスを許可するCORSの設定を広くしすぎることで、信頼していないWebサイトから情報を読み取られるなどの問題が発生する脆弱性です。

《 リスク概要 》

CORS(Cross-Origin Resource Sharing)は、あるWebサイトから別のオリジンにあるAPIなどへアクセスすることを、ブラウザ上で許可するための仕組みです。

例えば、

Web画面
https://app.example.jp

        ↓ APIアクセス

API
https://api.example.jp

のように、異なるオリジン間で通信する必要がある場合に利用します。

このとき、信頼していないWebサイトまで許可してしまうと、利用者が攻撃者のサイトを開いただけで、そのサイト上のJavaScriptから対象APIへアクセスされ、レスポンスの内容を読み取られる可能性があります。特に、Cookieなどの認証情報を伴うクロスオリジン通信を許可する場合は、許可するオリジンを厳密に制限する必要があります。

《 想定される被害・影響》

  • APIから個人情報や機密情報を読み取られる

  • ログイン中の利用者としてデータへアクセスされる

  • 信頼していないWebサイトからAPIを利用される

  • 管理画面や内部向けAPIの情報を取得される

《 対応方法 》

許可するオリジンを必要なWebサイトだけに限定する【必須】
クロスオリジン通信が必要な場合は、アクセスを許可するオリジンをサーバ側で明示的に管理します。

Access-Control-Allow-Origin: https://app.example.jp

複数のWebサイトを許可する場合も、あらかじめ許可したオリジンの一覧と Origin を照合し、一致した場合だけ許可してください。

https://app.example.jp     → 許可
https://admin.example.jp   → 許可
https://attacker.example   → 拒否

受信した Origin を確認せず、そのまま Access-Control-Allow-Origin として返す実装は避けます。

認証情報を送る場合は許可範囲を特に厳しくする【必須】
Cookieなどの認証情報をクロスオリジン通信で利用する場合は、

Access-Control-Allow-Credentials: true

を使用できますが、信頼するオリジンだけを明示的に許可してください。認証情報を伴うCORS通信では、Access-Control-Allow-Origin: * を使用することはできません。

許可するHTTPメソッドやヘッダーを必要なものだけにする【推奨】
クロスオリジン通信で利用するメソッドやリクエストヘッダーも、必要なものだけを許可します。

Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization

必要のない PUT、DELETE や任意のヘッダーまで広く許可しないようにします。

API側でも認証・認可を行う【必須】
CORSはブラウザからのクロスオリジン通信を制御する仕組みであり、APIのアクセス権限を保証するものではありません。CORSで許可・拒否している場合でも、各APIではリクエストごとに認証状態や権限をサーバ側で確認してください。→認証・認可チェックの不備


【システム情報・設定】


💻 例外処理の不備・エラー情報の公開

エラー発生時に詳細なエラー内容やシステム内部の情報を表示することで、攻撃者にシステム構成や攻撃の手掛かりを与えてしまう脆弱性です。

《 リスク概要 》

Webアプリケーションで例外や不正なリクエストが発生した際に、アプリケーションやWebサーバーが出力するエラー内容をそのまま利用者へ表示すると、攻撃者にシステム内部の情報を知られる可能性があります。

例えば、以下のような情報を外部へ表示すると、攻撃の手掛かりとして利用される可能性があります。

・スタックトレースやExceptionの詳細
・プログラムのファイル名や内部パス
・SQLやデータベースのエラー内容
・使用しているフレームワークやソフトウェアの情報
・サーバーや内部システムの構成情報
・存在するURL、機能、データなどを推測できるエラー情報

《 想定される被害・影響》

  • 使用しているソフトウェアやシステム構成を特定される

  • ファイルパスやデータベース構造などの内部情報を知られる

  • 存在する画面、API、管理機能などを特定される

  • SQLインジェクションなど、他の攻撃を行うための情報として利用される

  • 既知の脆弱性を持つソフトウェアを特定され、攻撃される

  • 想定外の例外によって処理が正常に終了しなくなる

《 対応方法 》

想定外のエラーを共通の例外処理で処理する【必須】
不正なリクエストや予期しない例外が発生した場合でも、アプリケーションやWebサーバーの詳細なエラー画面をそのまま表示せず、あらかじめ用意したエラー画面やエラーレスポンスを返します。個々の処理で捕捉できなかった例外についても、アプリケーション全体の共通エラー処理で受け取れるようにしてください。

利用者には、

処理中にエラーが発生しました。時間をおいて再度お試しください。

など、システム内部の情報を含まないエラーメッセージを表示します

詳細なエラー情報を利用者へ表示しない【必須】
スタックトレース、Exceptionの内容、SQL、内部パス、サーバー構成など、攻撃者の手掛かりとなる情報を画面やAPIレスポンスへ含めないようにします。本番環境では、フレームワークやWebサーバーのデバッグ画面・詳細エラー画面も無効にしてください。

エラーの違いから内部状態を推測されないようにする【推奨】
一般利用者向けのWebアプリケーションでは、エラーの種類によって画面やメッセージを細かく変えると、URLや機能の存在、認証状態などを推測される場合があります。

外部へ詳細な区別を知らせる必要がない場合は、400(不正なリクエスト)、401(認証が必要)、403(アクセス権限がない)、404(対象が存在しない)、405(許可されていない操作方法)などについて共通のエラー画面を表示し、利用者からエラーの種類やシステム内部の状態を判断しにくくします。

《 エラー画面の統一例 》

ただし、APIなどHTTPステータスコードによる判定が必要なシステムでは、仕様に応じたステータスコードを返しつつ、レスポンス本文に内部情報や詳細なエラー内容を含めないようにします。

詳細なエラー内容はサーバー側へ記録する【必須】
利用者へは簡潔なエラーメッセージのみを表示し、原因調査に必要な詳細情報はサーバー側のログへ記録します。ただし、パスワード、認証トークン、Cookie、クレジットカード情報、個人情報などの機密情報をそのままログへ記録しないようにしてください。

エラー時に処理を続行しない【必須】
例外やエラーが発生した場合に、認証・権限チェックなどの重要な処理を飛ばして後続処理を続行しないようにします。特に、確認できなかった場合に処理を許可してしまうFail-openにならないよう、エラー時は処理を中止し、安全な状態で終了してください。


💻 システム情報の開示

【簡単な説明】
サーバー、OS、Webサーバー、フレームワークなどの種類やバージョン、内部構成に関する情報を外部へ公開することで、攻撃者に攻撃の手掛かりを与えてしまう脆弱性です。

《 リスク概要 》

Webアプリケーションのレスポンスや画面などに、使用しているサーバーやソフトウェアの種類・バージョンなどが含まれていると、攻撃者がシステム構成を推測しやすくなります。これらの情報だけで直接攻撃されるわけではありませんが、使用している製品やバージョンを特定されることで、その製品に存在する既知の脆弱性を調査・攻撃する手掛かりとなります。

システム情報はHTTPヘッダーだけでなく、HTML、JavaScript、コメント、エラー画面などから公開される場合もあります。

《 想定される被害・影響》

  • 使用しているWebサーバーやフレームワークなどを特定される

  • ソフトウェアのバージョンを特定され、既知の脆弱性を狙われる

  • システム構成や使用技術を推測され、攻撃方法を絞り込まれる

  • 管理画面や内部機能などを探索するための情報として利用される

  • 他の脆弱性を攻撃するための事前調査に利用される

《 対応方法 》

不要なシステム情報を外部へ公開しない【必須】
アプリケーションの画面、HTML、JavaScript、コメント、APIレスポンスなどに、外部へ公開する必要のないサーバー名、内部パス、バージョン情報、システム構成などを含めないようにします。

HTTPレスポンスヘッダーから不要な製品情報を削除する【推奨】
X-Powered-By など、使用しているフレームワークや実行環境を知らせる不要なHTTPレスポンスヘッダーは削除します。

Server ヘッダーについても、Webサーバーの製品名や詳細なバージョン情報を必要以上に公開しないよう、使用しているWebサーバーやリバースプロキシの設定を確認します。

X-Powered-By: PHP/8.x.x
Server: Apache/2.x.x

のような詳細な製品・バージョン情報を、必要がないにもかかわらず外部へ公開しないようにしてください。

本番環境でデバッグ情報を公開しない【必須】
開発用のデバッグ画面、スタックトレース、フレームワークの詳細情報などが本番環境で表示されないように設定します。詳細なエラー情報については「例外処理の不備・エラー情報の公開」の対策とあわせて確認してください。→例外処理の不備・エラー情報の公開


💻 既知の脆弱性を含むソフトウェア・依存パッケージ

既知の脆弱性があるOS、サーバー、フレームワーク、ライブラリ、依存パッケージなどを使用し続けることで、既知の攻撃手法を利用して攻撃される脆弱性です。

《 リスク概要 》

Webアプリケーションは、さまざまなソフトウェアやライブラリを組み合わせて構成されています。これらに既知の脆弱性が残っていると、公開されている脆弱性情報や攻撃手法を利用して攻撃される可能性があります。また、直接利用しているパッケージだけでなく、そのパッケージが内部で利用する依存パッケージにも注意が必要です。

特に、サポートが終了したソフトウェアは、新しい脆弱性が発見されても修正版が提供されない場合があるため、継続利用には注意が必要です。

《 想定される被害・影響》

  • Webアプリケーションやサーバーを不正に操作される

  • 機密情報や個人情報を取得される

  • 不正なプログラムを実行される

  • サーバーやアカウントを乗っ取られる

  • データを改ざん・削除される

  • サービスを停止させられる

  • 脆弱な依存パッケージを経由してアプリケーション全体が侵害される

《 対応方法 》

利用しているソフトウェア・依存パッケージを把握する【必須】
OS、Webサーバー、実行環境、フレームワーク、ライブラリ、依存パッケージについて、使用している製品名とバージョンを把握できるようにします。直接利用しているパッケージだけでなく、内部で利用される依存パッケージについても管理対象とします。

パッケージの状態を定期的に確認する【必須】
利用しているソフトウェアやパッケージについて、既知の脆弱性、修正版、サポート終了日を定期的に確認します。脆弱性が見つかった場合は必要な修正版やパッチを適用し、サポート終了が近い場合は、安定版やLTSなどサポート対象バージョンへの移行を計画してください。

確認頻度は月1回程度を目安とし、重大な脆弱性が公開された場合は定期確認を待たず対応する必要があります。

依存パッケージの脆弱性チェックを自動化する【推奨】
SCA(Software Composition Analysis)などのツールを利用し、アプリケーションで使用している依存パッケージに既知の脆弱性がないか定期的に確認します。可能であれば、開発時だけでなくCI/CDなどにも組み込み、新しい脆弱性や脆弱なパッケージの追加を継続的に検出できるようにします。

CI(継続的インテグレーション):コードを変更したときに、ビルド・テスト・脆弱性チェックなどを自動実行する仕組み
CD(継続的デリバリー/デプロイ):テストを通過したプログラムを、検証環境や本番環境へ自動または半自動で反映する仕組

不要なソフトウェア・依存パッケージを削除する【推奨】
使用していないライブラリ、パッケージ、機能などを残しておくと、それらにも脆弱性管理が必要になります。利用していないものは削除し、管理対象を必要最小限にします。

アップデート後の動作確認を行う【必須】
脆弱性が修正された最新版でも、動作確認せず本番環境へ適用してはいけません。更新によって仕様・依存関係・設定方法などが変わり、システム障害が発生する可能性があります。

また、これまで不具合に依存して動作していた処理が、バグ修正によって動かなくなる場合もあります。更新内容を確認し、テスト環境で連携機能を含む基本全機能を検証したうえで、本番環境へ適用してください。


💻 ディレクトリリスティング・不要ファイル公開

Webサーバーの設定不備や不要ファイルの放置により、本来公開する必要のないファイルやディレクトリの内容が外部から閲覧できてしまう脆弱性です。

《 リスク概要 》

Webサーバーでディレクトリリスティングが有効になっていると、URLでディレクトリを指定した際に、その中のファイル一覧が表示される場合があります。

また、バックアップファイル、古いプログラム、設定ファイル、ログ、テスト用ファイルなどをWeb公開領域に残していると、画面からリンクされていなくてもURLを直接指定して取得される可能性があります。

《 想定される被害・影響》

  • 公開する予定のないファイルを取得される

  • ソースコードや設定情報を取得される

  • パスワード、APIキー、接続情報などの機密情報が漏えいする

  • バックアップファイルから過去のデータやソースコードを取得される

  • ファイル名やディレクトリ構成から、管理機能やシステム構成を推測される

  • 漏えいした情報を他の攻撃に利用される

《 対応方法 》

ディレクトリリスティングを無効にする【必須】
Webサーバーで、ディレクトリ内のファイル一覧を自動表示する機能を無効にします。Apache、Nginx、IISなどを利用する場合は、ディレクトリ一覧が外部へ表示されない設定になっていることを確認してください。

# Nginxでの設定例

server {
    location / {
        # ディレクトリ内のファイル一覧を表示しない
        autoindex off;
    }
}

不要なファイルをWeb公開領域へ置かない【必須】
バックアップ、テスト用ファイル、古いソースコード、ログ、設定ファイルなど、Webから直接取得する必要のないファイルは公開領域へ配置しないようにしてください。

次のようなファイルが残っていないかを確認
・.bak、.old、.backup などのバックアップ
・.git などの開発・バージョン管理情報
・設定ファイルや環境設定ファイル
・ログファイル
・テスト用・一時ファイル
・古いソースコードや圧縮ファイル

機密ファイルはWeb公開領域の外で管理する【必須】
設定ファイル、認証情報、内部データなど、外部へ公開する必要のないファイルはWeb公開領域の外に保存します。ファイルをWeb経由で提供する必要がある場合は、URLを直接指定すれば取得できる状態にせず、サーバー側で認証・権限チェックを行ったうえで提供してください。


💻 ソフトウェアサプライチェーン攻撃

依存パッケージやソフトウェアの取得・更新経路が侵害され、悪意のあるプログラムをシステムへ取り込んでしまう脆弱性です。

《 リスク概要 》

Webアプリケーションでは、多くの外部パッケージやライブラリを利用しています。正規パッケージの乗っ取り、偽パッケージ、依存パッケージの改ざんなどにより、開発者が気付かないまま悪意のあるコードを取り込む可能性があります。

また、直接利用しているパッケージだけでなく、そのパッケージが内部で利用する依存パッケージや、ビルド・配布・更新の仕組みが侵害される場合もあります。

《 想定される被害・影響》

  • APIキー、認証情報、個人情報などを盗まれる

  • 開発環境や本番サーバーで不正なプログラムを実行される

  • アプリケーションへ不正な処理を組み込まれる

  • 利用者の情報を外部へ送信される

  • 侵害されたパッケージを経由して多数のシステムへ被害が広がる

《 対応方法 》

信頼できる取得元からパッケージを利用する【必須】
公式レジストリや組織で管理された取得元を利用し、パッケージ名、提供元、更新内容などを確認してから追加します。名前が似ているだけのパッケージや、提供元が不明なパッケージを安易に利用しないようにします。

依存パッケージのバージョンを固定する【必須】
package-lock.json などのロックファイルを管理し、開発環境やCI/CD、本番環境で意図しない別バージョンがインストールされないようにします。ロックファイルはソースコードと一緒にバージョン管理し、勝手に書き換えたり削除したりしないようにします。

依存パッケージの追加・更新時に内容を確認する【必須】
新しいパッケージや更新版を取り込む際は、提供元や変更内容を確認し、テストしたうえで利用します。パッケージによってはインストール時にプログラムを実行するものもあるため、信頼できないパッケージをインストールするだけでも危険な場合があります。

依存関係を継続的に確認する【推奨】
CI/CDなどに脆弱性や依存関係のチェックを組み込み、新たな脆弱性や想定外の変更を継続的に検出できるようにします。必要に応じてSBOM(システムで使用しているソフトウェアやパッケージの一覧)を管理し、問題が発生したパッケージを使用しているシステムを確認できるようにします。


💻 初期パスワードやデフォルト管理画面の放置

製品やシステムの初期パスワード、初期アカウント、不要な管理画面などをそのまま残すことで、不正ログインや管理機能の悪用につながる脆弱性です。

《 リスク概要 》

OS、Webサーバー、ミドルウェア、管理ツールなどには、導入時から管理アカウントや管理画面、サンプル機能などが用意されている場合があります。初期ユーザー名・パスワードが変更されていなかったり、利用していない管理画面が外部からアクセスできたりすると、攻撃者に悪用される可能性があります。

特に、製品の初期アカウントや管理画面のURLは公開情報として知られている場合があるため、初期状態のまま本番環境で利用しないことが重要です。

《 想定される被害・影響》

  • 初期パスワードを利用して不正ログインされる

  • 管理者権限を取得される

  • システム設定を変更される

  • データを閲覧・変更・削除される

  • 不要な管理画面や機能を攻撃の入口として利用される

  • サーバーやシステム全体を乗っ取られる

《 対応方法 》

初期パスワード・初期アカウントをそのまま使用しない【必須】
製品やシステムを導入したら、初期パスワードを変更します。

使用しない初期アカウントやサンプルアカウントは、削除または無効化してください。

admin / admin
admin / password
root / 初期パスワード

など、製品にあらかじめ設定されている認証情報を本番環境でそのまま使用しないようにします。

不要な管理画面・管理機能を公開しない【必須】
使用していない管理画面、管理API、サンプルページ、テスト機能などは削除または無効化します。管理機能が必要な場合でも、一般利用者向けの画面と同じように無制限に公開せず、認証・権限チェックを必ず行います。

管理画面へのアクセス元を制限する【推奨】
管理画面をインターネット全体へ公開する必要がない場合は、社内ネットワーク、VPN、許可されたIPアドレスなどからのみアクセスできるように制限します。ただし、アクセス元の制限だけに依存せず、管理画面自体でも認証・権限チェックを行います。

本番環境へ公開する機能・設定を確認する【必須】
開発・検証環境で使用した管理機能、サンプルページ、テスト用アカウントなどが本番環境へ残っていないことを、リリース前に確認します。


💻 セキュリティログ・監視の不足

ログイン、権限変更、重要なデータ操作などが適切に記録・監視されていないことで、不正アクセスや攻撃の発生に気付けず、被害の拡大や事後調査が困難になる問題です。

《 リスク概要 》

Webアプリケーションで不正アクセスや攻撃が発生しても、必要なログが残っていなければ、

・誰が
・いつ
・どの機能やデータに対して
・どのような操作を行ったか

を確認できません。

また、ログを保存するだけで確認する仕組みがなければ、大量の認証失敗や権限違反などの不審な動きを検知できず、攻撃が長期間継続する可能性があります。

《 想定される被害・影響》

  • 不正ログインや不正操作の発見が遅れる

  • 攻撃が継続し、被害が拡大する

  • 情報漏えいなどが発生しても原因や影響範囲を特定できない

  • 誰が重要な操作を行ったのか確認できない

  • インシデント発生後の調査や対応が困難になる

《 対応方法 》

セキュリティ上重要な操作を記録する【必須】
不正アクセスの検知や事後調査に必要となる操作を記録します。

例えば、

・ログイン成功・失敗
・権限違反やアクセス拒否
・権限・ロールの変更
・重要なデータの登録・変更・削除
・管理者による重要な操作
・セキュリティ設定の変更

などを記録します。

ログには、日時、利用者、対象、操作内容、結果など、後から「誰が・いつ・何をしたか」を確認できる情報を含めます。

不審な動作を監視する【推奨】
大量のログイン失敗、短時間での大量アクセス、繰り返される権限違反など、攻撃の可能性がある動作を検知できるようにします。特に重要なシステムでは、重大な異常を検知した場合に管理者へ通知するなど、ログを保存するだけで終わらない仕組みを検討してください。

パスワードや認証情報をログへ記録しない【必須】
パスワード、セッションID、アクセストークンなど、漏えいすると不正利用につながる情報はログへ記録しないようにします。リクエスト内容などを記録する場合も、機密情報や個人情報は必要性を確認し、除外またはマスキングしてください。

ログを不正に変更・削除されないようにする【必須】
一般利用者からログへ直接アクセスできないようにし、ログの閲覧・変更・削除ができる権限を必要な管理者やシステムだけに限定します。また、外部から受け取った文字列をログへ記録する場合は、改行などによって偽のログを追加されたり、ログの形式を壊されたりしないよう適切に処理してください。


💻 APIキー/シークレット管理の不備

APIキー、データベースのパスワード、秘密鍵などをソースコードや公開可能な場所へ保存したり、必要以上の権限を与えたりすることで、漏えい時に外部サービスやシステムを不正利用される脆弱性です。

《 リスク概要 》

Webアプリケーションでは、外部APIやデータベース、クラウドサービスなどへ接続するために、APIキーやパスワードなどの秘密情報を利用します。

例えば、

APIキー
DBのユーザー名・パスワード
クラウドサービスのアクセスキー
秘密鍵
外部サービスの認証トークン

などがあります。

これらをソースコードへ直接書いたり、Gitなどのバージョン管理へ登録したりすると、コードの共有・公開・漏えいによって秘密情報も取得される可能性があります。OWASPも、APIキーなどのSecretsをソースコードへハードコードしないことを推奨しています。

また、漏えいしたシークレットに強い権限が設定されている場合、その権限を利用して被害が拡大する可能性があります。

《 想定される被害・影響》

  • 外部APIを不正利用される

  • データベースへ不正アクセスされる

  • クラウド上のデータやシステムを操作される

  • 機密情報や個人情報を取得される

  • API利用料金などを不正に発生させられる

  • 漏えいした認証情報を利用して他のシステムへ侵入される

《 対応方法 》

APIキーやシークレットをソースコードへ直接記述しない【必須】
APIキー、パスワード、秘密鍵などをプログラムへ直接書き込んだり、Gitなどのバージョン管理へ登録したりしないようにします。

ソースコード
    ↓
APIキーを直接記述      → 避ける

Secrets管理機能
    ↓
実行時に必要な値を取得 → 推奨

クラウドサービスや実行環境が提供するSecrets管理機能などを利用し、アプリケーションから必要なときに取得する設計を優先してください。OWASPもSecretsを一元的に管理し、アクセス制御や監査を行える仕組みの利用を推奨しています。

必要な権限だけを与える【必須】
APIキーやサービスアカウントには、そのアプリケーションが必要とする最小限の権限だけを設定します。例えば、データを読み取るだけの処理であれば、登録・変更・削除まで可能な権限を与えないようにします。

必要な処理:データ参照のみ

参照権限               → 許可
登録・変更・削除権限   → 与えない
管理者権限             → 与えない

これにより、シークレットが漏えいした場合でも被害を限定できます。

用途や環境ごとにシークレットを分ける【推奨】
開発環境、テスト環境、本番環境などで同じAPIキーや認証情報を使い回さないようにします。また、複数のシステムで同じシークレットを共有すると、一つのシステムから漏えいした場合に影響範囲が広がるため、可能な限り用途ごとに分けて管理します。

漏えいしたシークレットを速やかに失効・更新できるようにする【必須】
APIキーや認証情報が漏えいした、または漏えいが疑われる場合は、古いシークレットを失効させ、新しいものへ変更します。Secrets管理では、発行・利用・更新・失効といったライフサイクル全体を管理できるようにしてください。

ログや画面へシークレットを出力しない【必須】
APIキー、パスワード、アクセストークンなどをログ、エラー画面、デバッグ情報などへそのまま出力しないようにします。リクエストや設定情報をログへ記録する場合も、シークレット部分を除外またはマスキングしてください。


🧱 WAFなどの外部防御とアプリケーションセキュリティ

《 WAFとは 》

WAF(Web Application Firewall)は、WebアプリケーションへのHTTPリクエスト/レスポンスを監視し、SQLインジェクションやXSSなどの攻撃と判断した通信を検知・遮断する仕組みです。アプリケーションの手前で通信をチェックするため、攻撃を防ぐ追加対策として有効ですが、アプリケーション自体の脆弱性を修正するものではありません。

《 WAFによって脆弱性が隠れることに注意 》

WAFを経由してアプリケーションの脆弱性テストを行うと、攻撃用のリクエストがWAFで遮断され、アプリケーション内部に存在する脆弱性が表面化しないことがあります。そのため、アプリケーション自体の脆弱性確認と、WAFを含めたシステム全体の防御確認は分けて実施します。

《 正常なリクエストがWAFに遮断される場合 》

WAFは、正常な業務リクエストを攻撃と誤判定して遮断することがあります。そのため、正常な処理を通す目的で、特定のURLやパラメータについてルールを緩和したり、検査対象から除外したりする場合があります。このとき、それまでWAFによって遮断されていた攻撃も通るようになり、アプリケーション内部に存在していた脆弱性が表面化する可能性があります。

したがって、「WAFが止めているから、アプリケーション側では対策しなくてよい」という考え方は危険です。

《 WAF以外も同じ 》

API Gateway、CDN・Bot対策、CSP、RASPなども、アプリケーションを補助する追加の防御です。これらがあることを理由に、認証、認可、入力値検証、業務ロジックなどの対策を省略してはいけません。

《 AI・バイブコーディングでは特に注意 》

特に危険なのは、「AIで生成したプログラムでも、WAFを通せば安全」と考えることです。AIが生成したコードにも脆弱性が含まれる可能性があります。アプリケーション自体をレビュー・テストした上で、WAFを追加の防御として利用することが重要です

※ 重要 ※
WAFなどの外部防御がなくても、アプリケーション単体で安全であることを基本としてください。

アプリケーション側の対策 + WAFなどの追加防御

という多層防御で考えましょう。

《 WAFを利用する目安 》

まず誤解を生むかもしれませんので説明すると、セキュリティを考えるうえで、WAFの導入は必須ではありません。

しかし、次のようなWebアプリケーションでは、追加の防御として導入を検討すると良いでしょう。

・インターネットへ公開している
・個人情報、認証情報、決済情報などを扱う
・顧客向け・取引先向けなど、業務への影響が大きい
・管理画面や重要なAPIを公開している
・攻撃を受けた場合に、サービス停止や信用問題へつながる

特に、企業の基幹・業務システムや外部公開サービスでは導入を検討する価値が高くなります。ただし、WAFは誤検知への調整も必要になるため、開発負荷もかかり、かつ、導入するだけで安全になるものではありません。

《 WAFについて思う事(個人意見) 》

WEBアプリケーションのセキュリティ対策はプログラミングの世界なので、きちんと構造設計して対策するべきだと思います。そういう意味で、中身が分からないブラックボックスだけど何かしら守ってます的なWAFって、否定はしませんが個人的には好きではないんですよね。

WAFが正常な通信を止めることは多々あって、その理由を見ても理解できないことは多く、その場合、正常な通信を通すためにルールを緩和したり、一部を検査対象から除外したりする必要が出てきます。例えば、1行入力の場合は正常、3行入力の場合はエラー、といったケースをテストで拾えていないと、本番で「想定外にリクエストが拒否」されてサービスを止めてしまうことがあります。最悪ですね。

このリスクを避けるためには、アプリケーションのテストとは別に、WAFが正常なリクエストを誤って拒否しないことを確認するためのテストが必要になります。入力内容や文字数、改行、記号、ファイル内容など、さまざまなパターンでWAFだけのテストケースを作って確認しようとすると、かなりのコストがかかります。強固なシステムを要求される場合には必要なコストなのかもしれませんが……

ただ、日本企業がインターネットに公開しているWEBシステムって、アプリケーション側のセキュリティ対策が十分ではない状態で公開・運用されているケースが多々ある気がします。そんな雑なシステムを少しでも安全にしたいという使い方であればWAFは有効ではないかなぁという反面、この記事ではそれを明確に否定しているので悩ましいところです。


🔗 最後に

思ったより多くなりましたが、それなりに必要な脆弱性を網羅できたと思います。細かいところまで書き始めるとキリがないので、こういうのは「何を書かないか?」の方が重要になる気がします。

このセキュリティについては一般の人が仲間内で公開するようなWEBアプリの場合はそこまで考慮しなくても大丈夫かと思います。不特定多数の人に広く見てもらう場合はこのセキュリティ対策は必須になりますが、全て完璧な対応が必要かというとそうではなく、きちんとリスクを理解した上で、最悪の場合「何を失うのか?」を考えながら実装・公開を心がけて下さい。

この一覧はアプリケーション側からの脆弱性しか書いていませんので、インフラ側を含めるともっと多くなるはずですね。そちらは私の専門でもないですし、クラウドサービス上であればサービス側で管理される部分も多く、普通にWEBアプリケーションを開発する上では直接意識することはないかと思います。

また、WEBアプリケーションのセキュリティとバイブコーディングは、個人的にはかなり相性が悪いと思っています。バイブス(雰囲気的に人間がやりたいこと)を形にすることと、悪意を持った攻撃まで想定して防ぐことは別物と考えているからですね。セキュリティは利便性とのトレードオフや、認証・認可、データの持ち方など構造設計にまで踏み込むため、プロンプトやコンテキストにセキュリティ情報を詰め込んでも、適切に構造化される保証は本当にあるのか?って思います。

そうなると結局、自分が構造すら分からないプログラムの中身を解析しないと安心できず、解析したとて、バイブスのまま脆弱性を一つずつモグラたたき的に直していくと、かえって工数が増えてしまうことが見えるからです。構造レベルは人間がきちんと設計した上で、差分を確認しながら、上辺の実装にバイブコーディングを使うぐらいがちょうどよい気もします。

WEB脆弱性については日々変わっていきますので、定期的に見直してアップデートできればと考えています。もし、間違いや不足(これは絶対必要だと思う)ものがありましたら、ご指摘いただければと思います。

いいなと思ったら応援しよう!