説明
信頼できないデータを、レコードの区切り文字を無害化せずに行単位のログへ記録すると、ログインジェクションが発生します。キャリッジリターン(\r、CR)やラインフィード(\n、LF)でレコードの境界を作成・変更されると、偽のログの挿入、解析の妨害、調査の誤誘導につながります。
Pythonの logging APIは、位置引数(args)を msg に埋め込んでメッセージを作ります。logging.info("User: %s", user) のように書式引数を分けても、user に含まれるCR/LFは自動では無害化されません。
想定される影響
- ログの偽造: 偽の行を挿入し、重大度や形式が異なる記録に見せかけることができます。
- 自動解析の妨害: レコード形式が崩れ、収集処理やSIEMの解析・アラートに影響する可能性があります。
- 調査の信頼性低下: 時系列やユーザーの活動記録が不正確になり、調査や対応が遅れるおそれがあります。
対処方法
- 信頼できないメッセージや書式引数をロガーに渡す前に、CRとLFの両方を改行にならない文字へ置き換えます。
- 区切り文字をエスケープし、イベントごとに1レコードを出力するシリアライザーやフォーマッターを使います。キーと値の組にするだけでは、安全な構造化ログにはなりません。
- 標準のコンパクトな
json.dumps(...)は、CR、LF、U+0000〜U+001Fの制御文字をエスケープします。行単位のログではindentによる整形や、攻撃者が変更できるシリアライズ設定を使いません。 - 許可リストだけで対処する場合は、すべての候補が信頼できる有限のリテラル値で、CR/LFを含まないことが必要です。形式や長さの検証だけでは区切り文字を無害化できません。
- ログをHTMLで表示する場合は、ビューアーの出力時にHTMLエンコーディングも適用します。HTMLエスケープでは、保存されるログのCR/LFは無害化されません。
例
変更前
python
import logging
from flask import Flask, request
app = Flask(__name__)
@app.route('/search')
def search():
term = request.args.get('term', '')
# 書式引数を分けてもtermのCR/LFは残ります。
logging.info("Search term: %s", term)
return "ok"
変更後
CR/LFの置換
python
import logging
from flask import Flask, request
app = Flask(__name__)
@app.route('/search')
def search_safe():
term = request.args.get('term', '')
safe_term = term.replace("\r", " ").replace("\n", " ")
logging.info("Search term: %s", safe_term)
return "ok"
コンパクトなJSONへのシリアライズ
python
import json
import logging
from flask import request
def log_search():
term = request.args.get('term', '')
logging.info(json.dumps({"event": "search", "term": term}))
解説:
- 変更前:
termのCR/LFが書式処理後も残り、1つのイベントが複数の記録に見えるおそれがあります。 - CR/LFの置換: 両方の区切り文字を置き換えてから記録します。
- コンパクトなJSON: 標準の
json.dumps(...)は文字列内の制御文字をエスケープします。indentは出力自体を複数行にするため、行単位のログでは指定しません。
適用時の注意点
レコードの境界は、最終的なハンドラーとフォーマッターの設定に左右されます。実際の出力でCR/LFが適切に処理されることを確認し、ログビューアーではHTMLエンコーディングも適用してください。
参考資料
- CWE-117: ログ出力の不適切な無害化
- OWASP Logging Cheat Sheet
- OWASP Top 10:2025 A09 - Security Logging and Alerting Failures
- OWASP Top 10:2021 A09 - Security Logging and Monitoring Failures
- OWASP ASVS 5.0 V16 - Security Logging and Error Handling
- Python 3.14
loggingドキュメント - Python 3.14
jsonドキュメント - Flask 3.1のログに関するドキュメント