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

Spring Boot校验正则表达式引发栈溢出问题求助

解决正则表达式检测XSS引发的栈溢出问题

问题背景

我们为支持HTML格式的内容字段配置了XSS防护校验,通过正则表达式检测内容中是否包含script关键词(不区分大小写),若包含则抛出错误。但当内容长度达到约1000字符(阈值不固定)时,会触发StackOverflowError,短内容则校验正常,推测是正则递归回溯过多导致。

相关代码

涉及的Kotlin数据类:

data class UserMessageDto(
    val id: Long,
    val title: String,
    @get:Pattern(regexp = "^((?!(?i)(script))(.|\\r\\n|\\r|\\n))*$", message = "The word 'script' is not allowed in the message due to potential Javascript injection!")
    val message: String,
    val type: UserMessageType,
    val publicationDate: String?,
)

使用的正则表达式:

^((?!(?i)(script))(.|\\r\\n|\\r|\\n))*$

错误栈信息

java.lang.StackOverflowError: null
at java.base/java.util.regex.Pattern$Branch.match(Pattern.java:4734) ~[na:na]
at java.base/java.util.regex.Pattern$GroupHead.match(Pattern.java:4789) ~[na:na]
at java.base/java.util.regex.Pattern$Neg.match(Pattern.java:5181) ~[na:na]
at java.base/java.util.regex.Pattern$GroupHead.match(Pattern.java:4789) ~[na:na]
at java.base/java.util.regex.Pattern$Loop.match(Pattern.java:4898) ~[na:na]
at java.base/java.util.regex.Pattern$GroupTail.match(Pattern.java:4820) ~[na:na]
at java.base/java.util.regex.Pattern$GroupTail.match(Pattern.java:4820) ~[na:na]
at java.base/java.util.regex.Pattern$BranchConn.match(Pattern.java:4698) ~[na:na]
at java.base/java.util.regex.Pattern$CharProperty.match(Pattern.java:3931) ~[na:na]
// 后续栈信息重复

问题原因

原正则存在两个关键问题:

  1. 捕获组+量词导致栈累积:使用了捕获组((?!...)(...))*,Java的NFA正则引擎在处理带循环的捕获组时,每一次迭代都会将捕获组的匹配状态压入调用栈,长内容会快速耗尽栈内存。
  2. 重复的负前瞻检查:每匹配一个字符前都要执行一次(?!(?i)script)负前瞻校验,进一步增加了栈的开销,当字符数达到阈值时触发栈溢出。

解决方案

方案一:优化正则表达式

将原正则改为非捕获组形式,简化字符匹配逻辑,减少栈开销:

^(?:(?!(?i)script)[\s\S])*$
  • 用非捕获组(?:...)替代捕获组,避免栈中存储捕获组的状态;
  • 用[\s\S]匹配任意字符(包括换行),替代原写法(.|\r\n|\r|\n),更简洁高效;
  • 保留负前瞻逻辑,但减少不必要的栈操作。

方案二:改用字符串直接校验(推荐)

由于需求仅为检查内容是否包含script(不区分大小写),完全可以跳过正则,用字符串原生操作实现,彻底避免正则引擎的回溯问题:

  1. 自定义校验注解:
@Target(AnnotationTarget.PROPERTY_GETTER)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = NoScriptValidator::class)
annotation class NoScript(
    val message: String = "The word 'script' is not allowed in the message due to potential Javascript injection!",
    val groups: Array<KClass<*>> = [],
    val payload: Array<KClass<out Payload>> = []
)
  1. 实现校验器:
class NoScriptValidator : ConstraintValidator<NoScript, String> {
    override fun isValid(value: String?, context: ConstraintValidatorContext?): Boolean {
        return value?.lowercase()?.contains("script") != true
    }
}
  1. 修改数据类:
data class UserMessageDto(
    val id: Long,
    val title: String,
    @get:NoScript
    val message: String,
    val type: UserMessageType,
    val publicationDate: String?,
)

这种方式性能更高,逻辑更清晰,完全不会出现栈溢出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 22:23:11