[实践总结] 限制正则表达式匹配次数/时间 防止DoS攻击

思路

1、优化正则表达式

2、正则表达式无法优化的话,可以考虑限制匹配次数,或者限制匹配时间

限制 匹配次数

csharp 复制代码
public class CountedCharSequence implements CharSequence {
    private final CharSequence charSequence;
    private long count;

    public CountedCharSequence(CharSequence charSequence, long count) {
        this.charSequence = charSequence;
        this.count = count;
    }

    @Override
    public String toString() {
        return charSequence.toString();
    }

    @Override
    public int length() {
        return charSequence.length();
    }

    @Override
    public char charAt(int index) {
        if (index <= 0) {
            throw new IllegalArgumentException("Regex match over max " + count + " times");
        }
        count--;
        return charSequence.charAt(index);
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        return charSequence.subSequence(start, end);
    }
}

模拟Dos攻击

csharp 复制代码
String str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

long start = System.nanoTime();
Pattern.compile("^(a+)+$").matcher(str).matches();
System.out.println(((System.nanoTime() - start)) + " nano seconds");

执行用时
1399200 nano seconds

超过 1亿 就会报错

csharp 复制代码
long start1 = System.nanoTime();

try {
    Pattern.compile("^(a+)+$").matcher(new CountedCharSequence(str, 100_000_000)).matches();
} catch (Exception e) {
    System.out.println(e.getMessage());
}

System.out.println(((System.nanoTime() - start1)) + " nano seconds");

执行用时
Regex match over max 100000000 times
601800 nano seconds

限制 匹配时间

csharp 复制代码
import java.util.regex.Pattern;

public final class TimedCharSequence implements CharSequence {
    private final CharSequence sequence;
    private final long timestamp;

    public TimedCharSequence(CharSequence sequence, long nanoseconds) {
        this.sequence = sequence;
        this.timestamp = System.nanoTime() + nanoseconds;
    }

    @Override
    public String toString() {
        return sequence.toString();
    }

    @Override
    public int length() {
        return sequence.length();
    }

    @Override
    public char charAt(int index) {
        if (timestamp < System.nanoTime()) {
            throw new IllegalStateException("Regex match timeout");
        }
        return sequence.charAt(index);
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        return sequence.subSequence(start, end);
    }
}

模拟Dos攻击

csharp 复制代码
String str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

long start = System.nanoTime();
Pattern.compile("^(a+)+$").matcher(str).matches();
System.out.println(((System.nanoTime() - start)) + " nano seconds");

执行用时:
1385400 nano seconds

超过 给定时间间隔就报错

csharp 复制代码
long start1 = System.nanoTime();

try {
    Pattern.compile("^(a+)+$").matcher(new TimedCharSequence(str, 10_000)).matches();
} catch (Exception e) {
    System.out.println(e.getMessage());
}

System.out.println(((System.nanoTime() - start1)) + " nano seconds");

执行用时:
Regex match timeout
123100 nano seconds

Ref

Ref 限制正则表达式执行时间

相关推荐
ps酷教程6 小时前
Jackson 解决没有无参构造函数的反序列化问题
java
NiceCloud喜云6 小时前
Opus 4.8 的 Effort Control 怎么选:Low 到 Max 五档策略
android·java·大数据·前端·c++·python·spring
AI玫瑰助手7 小时前
Python函数:默认参数的定义与注意事项
开发语言·python·信息可视化
油炸自行车7 小时前
Claude Code 错误:API Error: 400 Failed to deserialize the JSON body into the
开发语言·javascript·json·trae·claude code·api error 400
肩上风骋7 小时前
C++14特性
开发语言·c++·c++14特性
_日拱一卒7 小时前
LeetCode:994腐烂的橘子
java·数据结构·算法·leetcode·深度优先
隔窗听雨眠7 小时前
Nginx网关响应慢排查手记
java·服务器·nginx
智慧物业老杨8 小时前
智慧物业合同周期管理系统:从风险预警到智能交接的全流程数智化落地方案
java·人工智能·python
源码宝8 小时前
MES系统源码:Java8 + SpringBoot2.7 + MySQL8 + Redis,后端源码清爽易扩展
java·后端·源码·springboot·mes系统·源码二开·mes源码
JAVA社区9 小时前
Java高级全套教程(十)—— SpringCloudAlibaba超详细实战详解
java·开发语言·spring cloud·面试·职场和发展