Securityチーム オーナーの松田です。
2025年5月に、OWASP ASVS の最新版である 5.0 がリリースされました。OWASP ASVS は、Webアプリケーションに対する一般的なセキュリティ要件をまとめたドキュメントです。非常に有用な一方で、約350の要件があり、すべてを読み込むには時間がかかります。さらに要件は抽象度が高く、実際のシステムに適用するには解釈が必要です。
本記事では、OWASP ASVS 5.0 の要件のうち、V1 エンコードとサニタイゼーションのレベル1を解説します。
OWASP ASVSとは
OWASP ASVS(Application Security Verification Standard)は、アプリケーションセキュリティを検証するための項目を体系的にまとめた標準です。テスト時のチェックリストとして利用できるだけでなく、開発時に参照するセキュリティ要件集としても活用できます。これにより、セキュリティを「後付け」ではなく「設計段階から組み込む」ことができます。
全体像については、以下の記事をご覧ください。

ASVS の各要件には3段階のレベルがあり、検証の強度を表します。主にシステムが取り扱うデータの機密性に応じて、どのレベルの要件を採用するかを決めます。なお、文書および要件テキストでは L1 / L2 / L3 と表記されます。
各レベルの要件は、概ね以下のとおりです。
- レベル1:インターネットに公開されるすべてのアプリケーション向け(基本的なセキュリティ)
- レベル2:機密データを扱う業務アプリケーション向け(より強固なセキュリティ)
- レベル3:高度な攻撃対象となるシステムや重要インフラ向け(最高レベルのセキュリティ)
たとえば、限定的な機密データしか扱わないスタートアップ企業は、初期の目標としてレベル1を選ぶかもしれません。一方、銀行のオンラインバンキングアプリケーションでは、レベル3相当を目標にすべきでしょう。一般的な個人情報を扱うWebアプリケーションであれば、レベル2相当まで実装すべきと考えます。
本記事では、レベル1に絞って解説します。
V1 Encoding and Sanitization(エンコーディングとサニタイゼーション)
では、早速、V1のレベル1要件を順に見ていきます。原文は英語のため、日本語で要点を整理しながら解説します。
V1.2 Injection Prevention(インジェクション対策)
1.2.1 HTTP レスポンス、HTML ドキュメント、XML ドキュメントの出力エンコーディングは、メッセージやドキュメント構造の変更を避けるために、HTML 要素、HTML 属性、HTML コメント、CSS、HTTP ヘッダフィールドに関連する文字をエンコードするなど、要求されるコンテキストに関連している。
早速、非常に抽象的ですねww
要するに、Cross-Site Scripting(XSS)などを防ぐため、出力先のコンテキストに応じて適切にエンコードする、という要件です。エンコードは「どこに出力するか」によって必要な処理が異なります。
- HTML要素
<p>HTML要素はここ</p>
例えば、ここにタグを含む文字列が入ると、HTML構造を壊される可能性があります。以下のような文字はエンコードが必要です。
< → <
> → >
& → &
- HTML属性
<input value="HTML属性はここ">
HTML要素の場合に加えて、" や ' にも注意が必要です。クォートをエンコードしないと、HTML構造を壊される可能性があります。属性を閉じて別の属性を注入されるおそれがあります。
<input value="test" onmouseover="alert(1)">
< → <
> → >
& → &
" → "
' → '
- HTMLコメント
<!-- HTMLコメントはここ -->
HTMLコメントでも、--> によってコメントを終了させると、その後に任意のHTMLを挿入できます。
<!-- HTMLコメントはここ-->
<script>alert(1)</script> -->
- CSSコンテキスト
<div style="color: CSSコンテキストはここ">
頻度は高くないかもしれませんが、CSSを動的に構築する場合はCSSコンテキストに合わせたエンコードが必要です。
- HTTPヘッダ
Location: /redirect?next=リダイレクトURLはHTTPヘッダ
代表例はリダイレクト先を設定する Location ヘッダです。ヘッダ値にCRLF(\r\n)が入ると、ヘッダの意味が変わり、ヘッダインジェクションが成立する可能性があります。改行を含ませない対策が必要です。
このように、コンテキストごとに必要なエンコードは異なります。
もう1つ重要なのは、この要件に「ユーザー入力を」とは書かれていない点です。DBに保存された値や外部APIから取得した値にも攻撃文字列が含まれる可能性があります。たとえば格納型 Cross-Site Scripting(XSS) 攻撃は、保存済みデータを表示したタイミングで成立します。
そのため、入力元を限定せず、すべての出力データに対してコンテキストに応じたエンコーディングを行うことが重要です。
1.2.2 URL を動的に構築する場合、信頼できないデータはそのコンテキストに応じてエンコードされている (例: クエリやパスパラメータの URL エンコーディングや base64url エンコーディング)。安全な URL プロトコルのみが許可されるようにしている (例: javascript: や data: を許可しない)。
この要件は比較的わかりやすく、クエリやパスパラメータに入るデータを URLエンコードや base64url エンコードで処理することを求めています。
?name=%E5%B1%B1%E7%94%B0%20%E5%A4%AA%E9%83%8E
加えて重要なのがURLスキームの制限です。javascript: や data: を許可しないなど、想定したスキームだけを許可する必要があります。こちらの方が重要ですね。
<a href="javascript:alert(1)">
通常は https:// のみを許可する方針が実装しやすく安全です。許可リスト方式で制御してください。
1.2.3 出力エンコーディングまたはエスケープは、JavaScript コンテンツ (JSON を含む) を動的に構築するときに使用され、メッセージやドキュメント構造の変更を回避している (JavaScript および JSON インジェクションを回避するため)。
この要件は、JSONを含む JavaScript コンテンツを動的に構築する際に、コンテキストに応じた出力エンコーディングまたはエスケープを行うことを求めています。
たとえば、以下のように JavaScript のコンテキストへデータを動的に挿入する場合を考えます。
<script>
var name = "コンテンツはここ";
</script>
"; alert(1); // のようなデータが入ると、alert が実行され、任意の JavaScript が実行される可能性があります。
<script>
var name = ""; alert(1); //";
</script>
注意点として、HTMLエンティティエンコードだけでは JavaScript コンテキストの対策として不十分です。このようなケースでは、JavaScript コンテキストに応じたエスケープを行う実装が必要です。
ただし、JavaScript に直接値を埋め込むより、いったん HTML の `data-*` 属性に出力してからデータとして参照するほうが安全で実装しやすいことが多いです。HTML属性コンテキストであれば、1.2.1 と同様の方針でエンコードを実装できます。
<div id="app" data-name="ここにデータをHTMLエンティティエンコードして入れる"></div>
<script>
const el = document.getElementById("app");
const name = el.dataset.name; // 文字列として取得
</script>
また、JSON データは HTTP API 経由で受け取り、文字列連結でスクリプトへ埋め込まない設計も有効です。
1.2.4 データ選択またはデータベースクエリ (SQL, HQL, NoSQL, Cypherなど) がパラメータ化クエリ、ORM、エンティティフレームワークもしくは他の方法により保護されており、SQL インジェクションや他のデータベースインジェクション攻撃の影響を受けない。これはストアドプロシージャを記述する際にも関係する。
これは、SQLインジェクションを含むデータベース向けインジェクション攻撃への対策要件です。具体的には、パラメータ化クエリ、ORM、フレームワーク機能などを使い、命令とデータを分離することを求めています。
つまり、文字列結合でクエリを組み立てないことが基本です。
- ダメな例:文字列結合でSQLを構成
String sql = "SELECT * FROM users WHERE name = '" + input + "'";
- 良い例:パラメータ化
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE name = ?"
);
ps.setString(1, input);
- ダメな例:ORMを使っていても文字列結合はNG
entityManager.createQuery("FROM User WHERE name = '" + input + "'");
- 良い例:パラメータにデータのみを渡す
userRepository.findByName(input);
詳しくは OWASP Injection Prevention Cheat Sheet を参照してください。
https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html
1.2.5 アプリケーションが OS コマンドインジェクションに対して保護していること、およびオペレーティングシステムコールがパラメータ化された OS クエリを使用するか、コンテキストに応じたコマンドライン出力エンコーディングを使用する。
1.2.5はOSコマンドインジェクション対策に関する要件です。まず前提として、アプリケーションからOSコマンドを実行しない設計が最優先です。たとえば、Linux の mkdir コマンドは多くの言語で標準ライブラリ関数で代替できます(PHPではmkdirという関数があります)。
どうしても必要な場合は、コマンド文字列をシェルに解釈させず、実行ファイルと引数を分離して渡します。Python では以下のように shell=False で実行します。
cmd: list[str] = ["ping", "-c", "1", host]
# shell=False が重要(デフォルトだが明示してもよい)
res = subprocess.run(
cmd,
shell=False,
check=True,
capture_output=True,
text=True,
timeout=3,
)
どうしても、パイプ(|)などでシェルを使う場合は、入力値を適切にクォートします。
safe_keyword = shlex.quote(keyword)
safe_filepath = shlex.quote(filepath)
cmd = f"grep -n {safe_keyword} {safe_filepath} | head -n 20"
res = subprocess.run(
cmd,
shell=True, # できれば避ける
check=True,
capture_output=True,
text=True,
timeout=3,
)
shlex.quote() はPOSIXシェル向けであり、Windowsでは別ルールになる点に注意してください。
また、実行結果をWebページやログに表示する場合は、表示先のコンテキストに応じたエンコーディング(例:HTMLエスケープ)も必要です。
V1.3 Sanitization(サニタイゼーション)
1.3.1 WYSIWYG エディタなどから取得した信頼できない HTML 入力はすべて、よく知られた安全な HTML サニタイゼーションライブラリもしくはフレームワークの機能を使用してサニタイズされている。
これはわかりやすい要件ではないかと思います。WYSIWYGエディタの入力にはHTMLタグが含まれますが、その内容は信頼できるとは限りません。したがって、無害化(サニタイゼーション)が必要です。要件では「よく知られた安全なライブラリまたはフレームワーク機能」の利用を求めています。
具体例は、Cross-Site Scripting Prevention Cheat Sheet の HTML Sanitization 章を参照してください。
https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#html-sanitization
1.3.2 アプリケーションが eval() や他の Spring Expression Language (SpEL) などの動的コード実行機能を使用しない。代替手段がない場合は、実行前に含まれるユーザー入力をサニタイズする必要がある。
eval() は使わないようにしてください。JavaScript の eval 関数は文字列をコードとして評価するため、入力が混入すると重大な脆弱性につながります。ほとんどのケースでその代替手段があると思いますので、原則として使わないようにしてください。
たとえば、JSONの解析に eval を使っている場合は JSON.parse に置き換え可能です。
V1.5 Safe Deserialization(安全なデシリアライゼーション)
1.5.1 アプリケーションは XML パーサーを制限する設定を使用し、XML 外部エンティティ(XML eXternal Entity, XXE)攻撃を防ぐために、外部エンティティ解決などの危険な機能を無効化している。
この要件は、XXE対策としてXMLパーサーを安全設定で動かすことを求めています。具体的には、DOCTYPE(DTD)や外部エンティティ解決を無効化し、外部リソース参照(file:// や http://)を遮断します。
XMLパーサーが外部エンティティを解決すると、ローカルファイル読み取りや http:// を使ったSSRFが発生し得ます。
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
XMLを扱う実装では、この要件への対応が必須です。
まとめ
本記事では、V1 Encoding and Sanitization のレベル1要件を解説しました。抽象度が高い要件もありますが、実装時には「コンテキストに応じた処理」「許可リスト方式」「安全な標準機能の利用」を軸に考えると整理しやすくなります。
解釈には筆者の見解も含まれます。もし認識違いがあれば、ぜひフィードバックをお願いします。
セキュアなシステム開発についての
\ 無料相談受付中! /

株式会社神戸デジタル・ラボ
デジタルビジネス本部 Securityチーム オーナー / 生産技術チーム
神戸大学情報知能工学科卒。2014年にKDLに入社。自社で構築するECサイトのほぼすべてのプロジェクトに関与しながら、多くの開発プロジェクトを経て、現在はSecurityチーム オーナーと全社のセキュア開発を推進する生産技術チームを兼任。開発部門主導のセキュア開発を実践している。
コミュニティ活動として、OWASP Kansaiボードメンバー、アルティメットサイバーセキュリティクイズ実行委員を務める。
【出典】
OWASP: Application Security Verification Standard
https://github.com/OWASP/ASVS
OWASP: XML External Entity Prevention Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
OWASP: Cross Site Scripting Prevention Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
OWASP: Injection Prevention Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html


