説明
入力に含まれるキャリッジリターン(\r、CR)や改行(\n、LF)がレスポンスヘッダーに入り、サーバー、プロキシ、受信側がメッセージの境界と解釈すると、レスポンス分割が起こり得ます。追加のヘッダーやレスポンスを注入されると、キャッシュ汚染やXSSにつながる可能性があります。
不正なヘッダー値を拒否・修正するサーバーもありますが、配備経路全体が同じ処理をするとは限りません。コンテナーの検証を有効にし、アプリケーションでも値の構文を確認してください。
想定される影響
- レスポンスを改ざんしたブラウザー動作の操作
- キャッシュ汚染による悪意あるコンテンツの配信
- 注入した本文が実行可能なマークアップとして解釈される場合のXSS
対処方法
- 信頼できない入力を直接ヘッダーに入れず、定義済みの値を優先してください。
- CR、LFや、そのヘッダーで許可されない制御文字を含む値を拒否してください。
- 利用者が値を選ぶ必要がある場合は、許可した集合に対応付け、そのフィールド固有の構文も検証してください。
例
変更前
java
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class InsecureResponseSplitting {
public void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
String userInput = request.getParameter("input"); // 入力を直接ヘッダーに渡す
response.setHeader("Custom-Header", userInput); // 未検証の入力
}
}
変更後
この独自ヘッダーでは、128文字以内の表示可能なASCIIだけを許可します。実際のヘッダーに固有の要件も確認してください。
java
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SecureResponseSplitting {
public void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
String userInput = request.getParameter("input");
if (!isValidHeaderValue(userInput)) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid input");
return;
}
response.setHeader("Custom-Header", userInput); // 検証した値だけを使用
}
private boolean isValidHeaderValue(String value) {
return value != null
&& value.length() <= 128
&& value.chars().allMatch(c -> c >= 0x20 && c <= 0x7e);
}
}
変更前は入力を直接setHeader()に渡します。受信経路がCR/LFを境界として扱うと危険です。変更後はisValidHeaderValue()で制御文字を拒否し、検証した値だけを設定します。Java文字列のエスケープはHTTPヘッダーの対策にはなりません。