SonarQube S5852安全热点:split方法正则回溯DoS问题解决方案
java:S5852正则DoS安全热点规避方案
java:S5852是SonarQube用于检测存在灾难性回溯风险正则的规则,这类正则在处理恶意构造的长输入时,会因回溯机制导致CPU占用飙升,最终触发拒绝服务。
你当前使用的正则(\\s*°\\s*)|(\\s*'{1,2}\\s*)风险点非常明确:两个匹配分支都以贪婪模式的\\s*开头,当输入存在连续长段空白、且后续没有命中°或单引号分隔符时,正则引擎会在两个分支之间反复回退重试,匹配耗时会随输入长度呈多项式级增长。
方案1:彻底弃用正则,手动实现拆分逻辑(最推荐)
你的拆分规则非常固定,完全没必要用正则实现。手动按字符遍历拆分的逻辑是线性时间复杂度,从根源上消灭ReDoS风险,性能也比正则高很多,逻辑和原有实现完全等价。
直接替换原有split调用即可:
private String[] splitLatStr(String input) { List<String> segments = new ArrayList<>(); StringBuilder cur = new StringBuilder(); int idx = 0, len = input.length(); while (idx < len) { char c = input.charAt(idx); // 跳过所有空白字符,自动过滤分隔符前后的空格 if (Character.isWhitespace(c)) { idx++; continue; } // 匹配°分隔符 if (c == '°') { segments.add(cur.toString().trim()); cur.setLength(0); idx++; continue; } // 匹配单引号/双单引号分隔符,优先匹配更长的''分隔符避免歧义 if (c == '\'') { idx += (idx + 1 < len && input.charAt(idx + 1) == '\'') ? 2 : 1; segments.add(cur.toString().trim()); cur.setLength(0); continue; } cur.append(c); idx++; } if (cur.length() > 0) { segments.add(cur.toString().trim()); } return segments.toArray(new String[0]); } // 业务代码替换原有split调用 String[] latData = splitLatStr(expPoint.getLatDegree()); if (latData.length == 4) { point.setLatitudeDegree(Integer.valueOf(latData[0])); point.setLatitudeMinute(Integer.valueOf(latData[1])); point.setLatitudeSecond(Double.valueOf(latData[2])); point.setLatitudeQuad("N".equals(latData[3])); }
这个实现可以正确处理分隔符前后任意数量的空白,也能准确区分'和''两种分隔符,和你原有正则的拆分结果完全一致,不存在行为差异。
方案2:优化正则结构,消除回溯路径
如果不想新增工具方法,也可以通过调整正则写法直接规避S5852检测,核心是切断正则的回溯路径:
// 优化后正则,无回溯风险 String splitRegex = "\\s*+(?:°|'{2}|')\\s*+"; String[] latData = expPoint.getLatDegree().split(splitRegex);
优化点说明:
- 把原来分散在两个分支的
\\s*前缀提取到公共位置,避免分支间因为匹配重叠内容产生回溯 - 空白匹配使用所有格量词
\\s*+,匹配到的空白字符不会被引擎回退,从根源上消除贪婪匹配带来的回溯风险 - 分隔符按最长优先顺序排列(先匹配
''再匹配'),避免匹配歧义
如果采用正则方案,建议额外加一层输入长度校验:合法的经纬度度分秒字符串长度通常不会超过30字符,超长输入直接判定为非法拦截,进一步降低风险。
内容的提问来源于stack exchange,提问作者tushar sharma
相关产品推荐
相关产品推荐

