You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HP Fortify检测到正则表达式DoS漏洞,求可行的验证方案

Mitigating Regex DoS Risks with Dynamic Configuration (Avoiding Hardcoding)

Great question—this is such a common pain point when balancing configurability and security. HP Fortify’s warning is spot-on: untrusted regex (even from config files, since they can be modified by admins or compromised) can trigger catastrophic backtracking, hogging CPU and causing a DoS. Let’s walk through actionable, practical solutions to fix this without ditching dynamic configuration.

Why the Risk Happens

First, a quick recap: regex patterns with nested quantifiers (like (a+)+b) or unbounded backtracking points can get stuck processing certain input strings, spinning the CPU indefinitely. This is the core of regex-based DoS attacks.

Solution 1: Validate Regex for Dangerous Patterns + Length Limits

Before compiling the regex from your .properties file, run a pre-check to block high-risk constructs and enforce reasonable length limits. This acts as a first line of defense.

Here’s a Java example of a validation method:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class RegexSecurityValidator {
    // Regex to detect common dangerous regex constructs: nested quantifiers, unbounded groups, etc.
    private static final Pattern DANGEROUS_CONSTRUCTS = Pattern.compile(
        ".*(\\([^)]*\\+\\)|\\+\\([^)]*\\)|\\*\\([^)]*\\)|\\{\\d+,\\}\\([^)]*\\)|" +
        "\\([^)]*\\)\\{\\d+,\\}|\\([^)]*\\)\\+|\\([^)]*\\)\\*|\\?=.*\\(|\\?<=.*\\()"
    );

    private static final int MAX_REGEX_LENGTH = 200; // Adjust based on your needs

    public static boolean isRegexSafe(String regex) {
        if (regex == null || regex.isBlank()) {
            return false;
        }
        // Block overly long regex (reduces attack surface)
        if (regex.length() > MAX_REGEX_LENGTH) {
            return false;
        }
        // Block patterns with high-risk backtracking potential
        Matcher dangerousMatcher = DANGEROUS_CONSTRUCTS.matcher(regex);
        return !dangerousMatcher.matches();
    }
}

Use this before compiling:

String regexFromConfig = properties.getProperty("app.validation.regex");
if (!RegexSecurityValidator.isRegexSafe(regexFromConfig)) {
    throw new IllegalArgumentException("Invalid or unsafe regular expression in config");
}
Pattern safePattern = Pattern.compile(regexFromConfig);

Solution 2: Enforce Timeouts for Compilation and Matching

Even with validation, edge cases can slip through. Java 9+ natively supports timeouts for regex operations, which prevent threads from getting stuck indefinitely. For older Java versions, use an executor service to wrap regex operations with time limits.

Java 9+ Example

import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class TimedRegex {
    public static void processWithRegex(String regex, String input) throws TimeoutException {
        // Set 1-second timeout for compilation
        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL, 1, TimeUnit.SECONDS);
        
        // Set 1-second timeout for matching
        Matcher matcher = pattern.matcher(input);
        if (matcher.find(1, TimeUnit.SECONDS)) {
            // Process match result
        }
    }
}

Java 8 and Below Example

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Pattern;

public class TimedRegexJava8 {
    public static Pattern compileWithTimeout(String regex, long timeoutSeconds) throws TimeoutException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Pattern> future = executor.submit(() -> Pattern.compile(regex));
        
        try {
            return future.get(timeoutSeconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            future.cancel(true); // Interrupt the stuck thread
            throw new TimeoutException("Regex compilation timed out");
        } finally {
            executor.shutdown();
        }
    }
}

Solution 3: Use a Safe Regex Engine

Swap Java’s default regex engine with a linear-time engine that avoids catastrophic backtracking entirely. Google’s re2j library is a great option—it’s designed to handle untrusted regex safely, with no risk of infinite loops.

Example with re2j

First, add the dependency (Maven):

<dependency>
    <groupId>com.google.re2j</groupId>
    <artifactId>re2j</artifactId>
    <version>1.7</version>
</dependency>

Then use it in your code:

import com.google.re2j.Pattern;
import com.google.re2j.Matcher;

public class SafeRegexEngine {
    public static boolean validateInput(String regexFromConfig, String input) {
        Pattern safePattern = Pattern.compile(regexFromConfig);
        Matcher matcher = safePattern.matcher(input);
        return matcher.matches();
    }
}

Note: re2j doesn’t support all Java regex features (like lookbehind assertions or backreferences in some cases), so test your existing regex patterns for compatibility first.

Solution 4: Regex Whitelisting (Most Secure Option)

If you don’t need fully arbitrary regex, use a whitelist of pre-vetted, safe regex patterns. Let your config file reference keys instead of raw regex, then map those keys to hardcoded, tested patterns.

Example

In your .properties file:

app.validation.regex.key=USER_ID_VALIDATOR

In your Java code:

import java.util.Map;
import java.util.regex.Pattern;

public class RegexWhitelist {
    private static final Map<String, Pattern> SAFE_REGEX_MAP = Map.of(
        "USER_ID_VALIDATOR", Pattern.compile("^[a-zA-Z0-9]{8,16}$"),
        "EMAIL_VALIDATOR", Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"),
        "PHONE_VALIDATOR", Pattern.compile("^\\+?[0-9\\s-]{10,15}$")
    );

    public static Pattern getPatternFromConfig(String configKey) {
        Pattern pattern = SAFE_REGEX_MAP.get(configKey);
        if (pattern == null) {
            throw new IllegalArgumentException("Unsupported regex key in config");
        }
        return pattern;
    }
}

This gives you configurability (you can switch which regex is used via config) while eliminating all regex DoS risk.

Which Solution Should You Choose?

  • Full custom regex needed: Combine validation (Solution 1) + timeouts (Solution 2) + re2j (Solution 3) for layered defense.
  • Limited regex use cases: Go with whitelisting (Solution 4)—it’s the most secure and low-maintenance option.

内容的提问来源于stack exchange,提问作者Vicky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:44:00