HTTPレスポンス分割

HTTPレスポンス分割

HTTPレスポンスヘッダーを分割攻撃から保護する

説明

HTTPレスポンス分割は、応答ヘッダーに改行文字を挿入して応答を分割し、攻撃者が操作した出力を追加する攻撃です。フレームワークやサーバーが改行を許容すると、XSSやキャッシュ汚染につながるおそれがあります。DjangoとWerkzeugはヘッダー内の改行を拒否するため、以下の未検証の例が直ちにレスポンス分割を許すわけではありません。不正な入力で例外が発生することがあります。

想定される影響

  • XSS: 挿入されたスクリプトがクライアントで実行される可能性があります。
  • キャッシュ汚染: 悪意ある内容がキャッシュされ、他の利用者に配信されるおそれがあります。
  • 情報漏えい: 改ざんされた応答で機密情報が漏えいする可能性があります。

対処方法

  • ヘッダーに入れる入力を検証し、改行文字(\r、\n)を除去します。
  • フレームワークのAPIでヘッダーを設定し、改行文字が拒否されることを確認します。

例

Django

変更前

python
# Djangoで入力を検証しない例
from django.http import HttpResponse

def unsafe_view(request):
    user_input = request.GET.get('input', '')
    response = HttpResponse()
    response['X-My-Header'] = user_input
    return response

変更後

python
# Djangoで改行を除去する例
from django.http import HttpResponse
import re

def safe_view(request):
    user_input = request.GET.get('input', '')
    sanitized_input = re.sub(r'[\r\n]', '', user_input)
    response = HttpResponse()
    response['X-My-Header'] = sanitized_input
    return response

解説:

  • 変更前: 入力をそのままヘッダーに渡します。改行を許容するかどうかによって、エラーやヘッダー挿入のリスクが生じます。
  • 変更後: ヘッダーを設定する前に改行を除去します。実際のヘッダーの用途に合った値の検証も必要です。

Flask

変更前

python
# Flaskで入力を検証しない例
from flask import Flask, request, Response

app = Flask(__name__)

@app.route('/unsafe')
def unsafe():
    user_input = request.args.get('input', '')
    response = Response()
    response.headers['X-My-Header'] = user_input
    return response

変更後

python
# Flaskで改行を除去する例
from flask import Flask, request, Response
import re

app = Flask(__name__)

@app.route('/safe')
def safe():
    user_input = request.args.get('input', '')
    sanitized_input = re.sub(r'[\r\n]', '', user_input)
    response = Response()
    response.headers['X-My-Header'] = sanitized_input
    return response

解説:

  • 変更前: 入力をそのままヘッダーに渡します。改行を許容するかどうかによって、エラーやヘッダー挿入のリスクが生じます。
  • 変更後: ヘッダーを設定する前に改行を除去します。実際のヘッダーの用途に合った値の検証も必要です。

FastAPI

変更前

python
# FastAPIで入力を検証しない例
from fastapi import FastAPI, Request, Response

app = FastAPI()

@app.get("/unsafe")
async def unsafe(request: Request):
    user_input = request.query_params.get('input', '')
    response = Response()
    response.headers['X-My-Header'] = user_input
    return response

変更後

python
# FastAPIで改行を除去する例
from fastapi import FastAPI, Request, Response
import re

app = FastAPI()

@app.get("/safe")
async def safe(request: Request):
    user_input = request.query_params.get('input', '')
    sanitized_input = re.sub(r'[\r\n]', '', user_input)
    response = Response()
    response.headers['X-My-Header'] = sanitized_input
    return response

解説:

  • 変更前: 入力をそのままヘッダーに渡します。改行を許容するかどうかによって、エラーやヘッダー挿入のリスクが生じます。
  • 変更後: ヘッダーを設定する前に改行を除去します。実際のヘッダーの用途に合った値の検証も必要です。

参考資料