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 の欠陥を報告します。

修正されたコード例

ヘッダーフィールド内での安全な使用のために、入力を検証する多数のヘルパーメソッドを実装できます。

Restriction: メソッド 1 と 2 は改行の存在のみをチェックします。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";
    }

拡張機能

このチェッカーは、Klocwork knowledge base (ナレッジベース) を利用して拡張できます。詳細については、Java 解析のチューニングを参照してください。