SV.HTTP_SPLIT
HTTP 応答分割
このエラーは、HTTP ヘッダーに書き込むメソッドに HTTP クライアントやデータベースの値が検証なしで表示される場合に報告されます。SV.XSS.* チェッカーも同様の攻撃に対応します。
このチェッカーは、入力検証が矛盾なく使用されていることを確認するのに便利です。特定の検証ユーティリティを使用してコードが設計され、適切な注釈がナレッジベースファイルに追加されていると、このチェッカーにより、検証が行われなかったコードパスの指摘が報告されます。 Java 解析のチューニング を参照してください。
リリース 2023.2 の時点で、このチェッカーは Jakarta EE をサポートしています。
脆弱性とリスク
HTTP 応答分割 は、アプリケーションの攻撃技法の 1 つです。これにより、Web キャッシュポイゾニング、クロスユーザー改ざん、機密のユーザー情報を持つページのハイジャック、クロスサイトスクリプティング (XSS) などの新たな攻撃が可能になります。この攻撃手法およびここから派生した攻撃は、ほとんどの Web 環境で起こり得ます。これらは、悪意のある文字や予期しない文字が含まれる不正なユーザー入力を拒否しないアプリケーションが原因となって発生します。
HTTP 応答分割とは、Web サーバーに出力ストリームを強制的に構成させる単一の HTTP 要求を攻撃者が送信し、ターゲットからは、通常の単一応答ではなく、2 つの HTTP 応答に解釈されるように仕込まれていることです。最初の応答は、攻撃者によって部分的に制御されている場合もありますが、それほど重要ではありません。重要な点は、2 番目の応答 (ヘッダー) の形式を攻撃者が完全に制御していることです。これが可能になると、攻撃者は、ターゲットを経由して 2 つの要求を送信することにより、攻撃を完成させることができます。最初の要求は Web サーバーから 2 つの応答を引き出し、2 番目の要求は Web サーバー上の無防備なリソースを利用します。しかし、ターゲットによる 2 番目の要求は、攻撃者に完全に制御された 2 番目の HTTP 応答と対応付けられます。このようにして、攻撃者は、2 番目の要求によって指定された Web サーバー上の特定のリソースがサーバーの HTTP 応答 (サーバーのコンテンツ) であるとターゲットに信じ込ませます。もちろん、これは Web サーバー経由で偽造されたデータ (2 番目の応答) です。
Klocwork セキュリティ脆弱性 (SV) チェッカーは、潜在的に危険なデータを生成する呼び出しを特定します。このような呼び出しは安全でないソースと考えられます。ユーザーは攻撃者になる可能性があり、ヒューマンエラーを取り込む可能性があるため、安全でないソースはユーザーが指定した任意のデータである可能性があります。
軽減と防止
やや信頼できるソース (データベースなど) からの入力を含め、すべての入力データを検証します。特に、キャリッジリターンとその後に続くラインフィードの組み合わせ (CRLF) についてチェックします。
脆弱コード例 1
import javax.servlet.http.*;
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String url = req.getParameter("HIDDEN_URL");
if (url.length() == 0) {
generatePage(req, resp);
} else {
resp.sendRedirect(url);
}
}
private void generatePage(HttpServletRequest req, HttpServletResponse resp) throws IOException {
PrintWriter wr = resp.getWriter();
wr.print("Hello, World!");
}
Klocwork は、7 行目で SV.HTTP_SPLIT の欠陥を報告し、次を示します。'url' には HTTP 要求パラメーターからのデータが含まれているため、汚染される可能性があります (3 行目)。この値は、20 行目で HTTP リダイレクトの送信に使用されます。
脆弱コード例 2
import jakarta.servlet.http.*;
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String url = req.getParameter("HIDDEN_URL");
if (url.length() == 0) {
generatePage(req, resp);
} else {
resp.sendRedirect(url);
}
}
private void generatePage(HttpServletRequest req, HttpServletResponse resp) throws IOException {
PrintWriter wr = resp.getWriter();
wr.print("Hello, World!");
}
Klocwork は、7 行目で SV.HTTP_SPLIT の欠陥を報告し、次を示します。'url' には HTTP 要求パラメーターからのデータが含まれているため、汚染される可能性があります (3 行目)。この値は、20 行目で HTTP リダイレクトの送信に使用されます。
脆弱なコード例 3
@GetMapping("/vuln")
public String vuln(HttpServletResponse response, HttpServletRequest request) throws IOException {
response.sendRedirect(request.getParameter("HIDDEN_URL"));
return "Response with header using HttpServletResponse";
}
3 行目で HTTP 要求パラメーターからデータを取得しているため、Klocwork は SV.HTTP_SPLIT の欠陥を報告します。
修正されたコード例
ヘッダーフィールド内での安全な使用のために、入力を検証する多数のヘルパーメソッドを実装できます。
メソッド 1
入力文字列を検証し、ヘッダー分割の危険をもたらさないことを確認します。
private static String validateNoSvHttpSplitOrThrow(String s) throws IllegalArgumentException{
if (s.contains("\r") || s.contains("\n")){
throw new IllegalArgumentException("unexpected SV.HTTP_SPLIT hazard");
}
return s;
}
パラメーターが安全でない場合は、例外がスローされます。
メソッド 2
ヘッダー分割攻撃に関する安全性について、パラメーターを検証します。
private static boolean validateNoSvHttpSplit(String s) {
if (s.contains("\r") || s.contains("\n")){
return false;
}
return true;
}
パラメーターの使用が安全である場合、メッセージは true を返します。
メソッド 3
カスタム Java KB を適用して、ヘルパー関数に注釈を付けます。
@Bind("SV.HTTP_SPLIT")
public class WelcomeController {
private static String validateNoSvHttpSplitOrThrow(@Check String s);
private static boolean validateNoSvHttpSplit(@CheckTrue String s);
}
注釈付きヘルパーを使用して、パラメーターの安全性を確保します。
@GetMapping("/checked_except")
public String checkedExcept(HttpServletResponse response, HttpServletRequest request) throws IOException {
response.sendRedirect(validateNoSvHttpSplitOrThrow(request.getParameter("HIDDEN_URL")));
return "Response with header using HttpServletResponse";
}
@GetMapping("/checked_except")
public String checkedExcept2(HttpServletResponse response, HttpServletRequest request) throws IOException {
String hidden_url = request.getParameter("HIDDEN_URL");
validateNoSvHttpSplitOrThrow(hidden_url);
response.sendRedirect(hidden_url);
return "Response with header using HttpServletResponse";
}
@GetMapping("/checked_bool")
public String checkedBool(HttpServletResponse response, HttpServletRequest request) throws IOException {
String hidden_url = request.getParameter("HIDDEN_URL");
if (validateNoSvHttpSplit(hidden_url)) {
response.sendRedirect(validateNoSvHttpSplitOrThrow(hidden_url));
}else{
return "do something else";
}
return "Response with header using HttpServletResponse";
}
外部参考資料
セキュリティトレーニング
Secure Code Warrior が提供しているアプリケーションセキュリティトレーニング教材。
拡張機能
このチェッカーは、Klocwork knowledge base (ナレッジベース) を利用して拡張できます。詳細については、Java 解析のチューニングを参照してください。