0Pricing
Security+ Academy · レッスン

入力検証と出力エンコーディング

サーバー側の入力検証とコンテキスト対応の出力エンコーディングを実装し、悪用される前にインジェクションやXSSの脆弱性を無害化します。

「入力検証と出力エンコーディング」はCoddyKit上の無料Security+ Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSecurity+ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Security+ Academyコースには全4レッスンが含まれています。

入力が危険な理由

アプリケーションが外部から受け取るあらゆるデータ(ユーザーのフォーム入力、URLパラメーター、HTTPヘッダー、APIリクエスト本文、ファイルアップロード)は、潜在的に攻撃者が制御できるデータです。検証を行わないと、攻撃者はSQLコマンド、HTMLスクリプト、シェルコマンド、XML/LDAPディレクティブをアプリケーションのデータフローに注入できます。入力検証と出力エンコーディングは、インジェクションの脆弱性が被害を引き起こす前に無効化する、2つの中核的な対策です。

入力検証とは

入力検証は、受け取ったデータがアプリケーションによる処理前に、想定された型、形式、長さ、値の範囲に適合していることを確認します。検証はサーバー側で行う必要があります。JavaScriptによるクライアント側検証は、Burp Suiteなどのツールでリクエストを傍受する攻撃者によって簡単に回避されるためです。ユーザー名には英数字のみを受け付け、日付フィールドには有効な日付形式のみを受け付け、メールフィールドはRFC 5322の構文に適合させる必要があります。

# Server-side input validation examples:

# Validate username: allow only alphanumeric and underscore
# Pattern: ^[a-zA-Z0-9_]{3,20}$
# Reject: 'admin--', "' OR 1=1--", '<script>alert(1)</script>'

# Validate age: must be integer between 0 and 120
# Reject: -1, 999, 'abc', '18; DROP TABLE users'

# Validate email: match RFC 5322 pattern, max 254 chars
# Reject: 'a@b' (too short), attacker@evil.com<script>...

AllowlistとDenylistによる検証

Allowlist(whitelist)検証は、許可されるものを正確に指定し、それ以外をすべて拒否します。Denylist(blacklist)検証は、許可されないものを指定し、それ以外をすべて許可します。攻撃者はdenYlistを回避する新しい手法を継続的に発見するため、常にAllowlist検証が推奨されます。たとえば、SQLインジェクションのdenylistはSELECT、UNION、--などをブロックしようとしますが、巧妙なエンコードによってこれらのフィルターを回避されることがあります。数値フィールドに数字だけを許可するAllowlistは回避できません。

# Allowlist (GOOD): only allow expected characters
# username_pattern = '^[a-zA-Z0-9_]{3,20}$'
# If input does not match -> reject with 400 Bad Request

# Denylist (WEAK): try to block known-bad patterns
# reject_patterns = ["'", '--', 'UNION', 'SELECT', 'DROP']
# Problem: attacker uses: SE%00LECT, UNION%0aALL, encoded chars
# Denylist is incomplete by definition -> prefer allowlist

パラメーター化クエリによるSQLインジェクション防止

データベースとのやり取りでは、パラメーター化クエリ(prepared statements)がSQLインジェクションに対する決定的な防御策です。クエリの構造をユーザー提供のデータとは別に定義するため、データベースエンジンが入力をSQL構文として解釈することはありません。ユーザーが' OR '1'='1と入力しても、実行可能なSQLではなく、リテラル文字列のパラメーターとして扱われます。パラメーター化クエリは、主要なすべての言語とデータベースドライバーで利用できます。

# VULNERABLE: string concatenation (SQL injection possible)
# query = 'SELECT * FROM users WHERE name = ' + user_input
# Attack: user_input = "' OR '1'='1" -> returns ALL users

# SAFE: parameterized query
# query = 'SELECT * FROM users WHERE name = ?'
# cursor.execute(query, (user_input,))
# The ? is a placeholder; user_input is passed separately
# The DB driver handles escaping automatically
# Attack input: "' OR '1'='1" -> treated as literal string

出力エンコーディングとは

出力エンコーディングは、データを出力コンテキスト(HTML、JavaScript、SQL、URL、シェルコマンド)に挿入する前に、データ内の特殊文字を変換します。これにより、あるコンテキストのデータが別のコンテキストで実行可能なコードとして解釈されるのを防ぎます。重要な原則はコンテキストを意識したエンコーディングです。適用するエンコーディングは出力コンテキストに合わせる必要があります。HTMLエンコーディング、URLエンコーディング、JavaScriptエンコーディング、シェル引数のクォートは、それぞれのコンテキストでインジェクションを無効化します。

HTML出力エンコーディングによるXSS防止

ユーザーが提供したデータをHTMLに表示する場合、Cross-Site Scripting(XSS)を防ぐために特殊文字をHTMLエンコードする必要があります。文字<は&lt;に、>は&gt;に、&は&amp;になります。攻撃者が<script>alert('XSS')</script>を入力しても、HTMLエンコーディングによってスクリプトは実行されず、表示テキストとして描画されます。すべてのWebフレームワークにはHTMLエンコーディング関数が用意されているため、一貫して使用してください。

# Without encoding (VULNERABLE to XSS):
# html = '<p>Hello, ' + username + '</p>'
# If username = '<script>document.cookie</script>'
# -> script executes in victim browser

# With HTML encoding (SAFE):
# html = '<p>Hello, ' + html_encode(username) + '</p>'
# html_encode('<script>...') -> '&lt;script&gt;...&lt;/script&gt;'
# -> Displays as text, not executable script

コンテキスト固有のエンコーディング規則

出力コンテキストが異なれば、必要なエンコーディング戦略も異なります。HTML本文:< > & ' "をエンコードします。HTML属性:同じ文字をエンコードし、属性を引用符で囲むことも徹底します。JavaScriptコンテキスト:JSONエンコーディングまたはJavaScript文字列エスケープを使用します。URLパラメーター:特殊文字にパーセントエンコーディングを適用します。シェルコマンド:ユーザー入力からシェルコマンドを組み立てること自体を避け、シェルインタープリターに対する文字列連結ではなく、引数配列を受け取る言語APIを使用します。

# Context-aware encoding examples:

# HTML body context:
# safe_html = '&lt;script&gt;' (renders as text)

# URL parameter context:
# safe_url = 'search?q=hello%20world%26more'

# JavaScript string context (in JSON):
# safe_js = '{"name": "O\\u0027Reilly"}'

# Shell command (AVOID string concat - use array instead):
# UNSAFE: os.system('ping ' + user_input)
# SAFE:   subprocess.run(['ping', '-c', '1', user_input])

複数レイヤーでの検証

入力検証はAPIエンドポイントだけでなく、複数のレイヤーで実施する必要があります。クライアント側検証は、即時フィードバックによってユーザー体験を向上させますが、セキュリティ対策として決して信頼してはいけません。API/コントローラー検証が主要なセキュリティレイヤーです。サービス/ビジネスロジック検証はドメインルールを適用します。データベース制約(NOT NULL、CHECK、FOREIGN KEY)は最後の防御レイヤーとなります。多層防御とは、1つのレイヤーを回避されても、直ちに悪用につながらないようにする考え方です。

ファイルアップロードの検証

ファイルアップロードの入力は特に危険です。攻撃者は、画像を装ったWebシェル、マクロを含む悪意のあるドキュメント、またはサイズの大きすぎるファイル(DoS)をアップロードします。検証には、拡張子だけでなく内容(マジックバイト)によるファイル種別の確認、最大ファイルサイズの適用、Webルート外へのアップロードファイルの保存、予測可能なパスを防ぐためのサーバー上でのファイル名変更、ウイルス対策/サンドボックスによるスキャンを含める必要があります。また、アップロードされたファイルを直接実行してはいけません。

# File upload validation steps:
# 1. Check Content-Type header (client-provided, not trusted alone)
# 2. Read first bytes (magic bytes):
#    JPEG: FF D8 FF | PNG: 89 50 4E 47 | PDF: 25 50 44 46
# 3. Reject if magic bytes don't match expected type
# 4. Enforce max size: reject > 10MB
# 5. Strip original filename, assign random UUID filename
# 6. Store in /var/uploads/ (NOT /var/www/html/)
# 7. Serve via CDN or application route (not direct URL)

APIにおける入力検証

最新のアプリケーションではREST APIとGraphQLが広く利用されているため、JSON/XMLリクエスト本文の検証が必要です。JSON SchemaなどのAPI検証フレームワークでは、必須フィールド、データ型、文字列パターン、値の範囲を定義できます。GraphQLの深さ制限により、深くネストされたクエリによるDoSを防止できます。リクエストレート制限は、個々の入力が有効であっても自動化された悪用を防ぎます。スキーマ検証は、ビジネスロジックでリクエストを処理する前に実施する必要があります。

# JSON Schema validation example:
# POST /api/register body schema:
# {
#   'type': 'object',
#   'required': ['username', 'email', 'password'],
#   'properties': {
#     'username': {'type': 'string', 'pattern': '^[a-zA-Z0-9_]{3,20}$'},
#     'email':    {'type': 'string', 'format': 'email', 'maxLength': 254},
#     'password': {'type': 'string', 'minLength': 12, 'maxLength': 128}
#   },
#   'additionalProperties': false
# }

エラーメッセージと情報漏えい

ユーザーに返されるエラーメッセージは、攻撃者に役立つ機密情報を意図せず公開する可能性があります。データベースのエラーメッセージからは、テーブル名、カラム型、SQL構文が明らかになることがあります。スタックトレースからは、アプリケーションフレームワークのバージョンやファイルパスが漏えいします。詳細な入力検証エラーは、どの文字が拒否されたかを攻撃者に確認させ、回避方法の作成を助ける可能性があります。ベストプラクティスは、クライアントには一般的でユーザーに分かりやすいエラーメッセージ(例:「入力が無効です」)を返し、開発者のデバッグ用に詳細なエラー情報をサーバー側でログに記録することです。エンドユーザーに生の例外メッセージを公開してはいけません。

# UNSAFE: returning detailed database error to user
# Error: 'You have an error in your SQL syntax near ... at line 1'
# Reveals: database type (MySQL), partial query structure

# UNSAFE: stack trace in API response
# Error: 'java.sql.SQLException at com.company.UserDAO.findByName:47'
# Reveals: framework (Java), class names, line numbers

# SAFE: generic error response to client
# HTTP 400 Bad Request: { 'error': 'Invalid request parameters' }
# Server log (internal only): full exception with stack trace
# Monitoring: alert on high error rates -> investigate internally

クイックチェック

このレッスンで扱ったCompTIA Security+(SY0-701)の概念について、理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、Allowlistを使用したサーバー側の入力検証によって想定されたデータだけが処理されること、パラメーター化クエリによってデータとクエリ構造を分離しSQLインジェクションを防止できること、そしてコンテキストを意識した出力エンコーディングによって、HTML、JavaScript、URL、シェルのコンテキストに入る前に特殊文字を無効化し、XSSやその他のインジェクション攻撃を防止できることを学びました。次は、安全なシークレット管理と環境変数インジェクションについて学びます。

よくある質問

「入力検証と出力エンコーディング」レッスンは無料ですか?

はい。「入力検証と出力エンコーディング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Security+ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Security+ Academyコースには全4レッスンが含まれています。

「入力検証と出力エンコーディング」で何を学びますか?

サーバー側の入力検証とコンテキスト対応の出力エンコーディングを実装し、悪用される前にインジェクションやXSSの脆弱性を無害化します。 ブラウザで直接実行するハンズオンコードでSecurity+ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Security+ Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのSecurity+ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「入力検証と出力エンコーディング」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このSecurity+ Academyレッスンでコードを書いて実行できますか?

はい。すべてのSecurity+ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 入力検証と出力エンコーディング
  2. 安全なシークレット管理と環境変数
  3. 依存関係のセキュリティとソフトウェア構成分析
  4. DevSecOps:セキュリティをパイプラインに前倒しする
← Security+ Academyに戻る