一、项目背景:
Hello-Java-Sec项目为 Github中 一个面向安全开发的 Java漏洞代码审计靶场。
靶场地址:https://github.com/j3ers3/Hello-Java-Sec 本地使用idea部署即可
二、代码审计:
通过阅读代码可知,代码采用 @RequestMapping 注解的方式来处理 HTTP不同方法的请求,故采用 全局搜索@RequestMapping注解来查看路由的方式,进行进一步的审计。
(一)、SQL注入:
1、JDBC注入:
(1)、语句拼接,过滤不当导致SQL注入:
未对用户传入的 id 值进行判断过滤,导致产生SQL注入
可采用黑名单的方式,对敏感字符进行过滤操作:
public static boolean checkSql(String content) {
String[] black_list = {"'", ";", "--", "+", ",", "%", "=", ">", "*", "(", ")", "and", "or", "exec", "insert", "select", "delete", "update", "count", "drop", "chr", "mid", "master", "truncate", "char", "declare"};
for (String s : black_list) {
if (content.toLowerCase().contains(s)) {
return true;
}
}
return false;
}
(2)、预编译使用不当导致SQL注入:
虽然使用了 prepareStatement()方法进行预编译,但是并没有使用 ? 进行占位,导致代码本质上还是 sql语句的拼接,导致产生SQL注入。
可采用 ? 进行占位处理,修复代码如下:
public String safe1(String id) {
String sql = "select * from users where id = ?";
PreparedStatement st = conn.prepareStatement(sql);
st.setString(1, id);
ResultSet rs = st.executeQuery();
}
靶场还给出了另外两种可以防御SQL注入的代码,如下所示:
(1) ESAPI安全框架:
// ESAPI 是一个免费、开源的、网页应用程序安全控件库,它使程序员能够更容易写出更低风险的程序
// 官网:https://owasp.org/www-project-enterprise-security-api/
public String safe3(String id) {
Codec<Character> oracleCodec = new OracleCodec();
Statement stmt = conn.createStatement();
String sql = "select * from users where id = '" + ESAPI.encoder().encodeForSQL(oracleCodec, id) + "'";
ResultSet rs = stmt.executeQuery(sql);
}
其中 encodeForSQL方法对输入的特殊字符进行了转义处理,例如单引号 ' 会被转义为 ''。
(2) 强制数据类型:
// 如果参数类型为boolean,byte,short,int,long,float,double等,sql语句无法拼接字符串,因此不存在注入
public Map<String, Object> safe4(Integer id) {
String sql = "select * from users where id = " + id;
return jdbctemplate.queryForMap(sql);
}
若进行字符串拼接,会进行报错处理,提示我们需要输入一个 Integer类型,而不是String类型的值。
2、MyBatis框架中的SQL注入:
MyBatis框架:MyBatis 自动处理 JDBC 的繁琐工作,如建立连接、准备和执行 SQL 语句、处理结果集等。它简化了 JDBC 编程,提供了强大的动态 SQL 功能,并且支持多种数据库。
(1) 搜索框注入 ('%#{q}%' 和 '%${q}%' 使用不当):
用户输入的任意值被复制给参数q,并使用search()方法进行操作,跟进search()方法:
search()方法中采用 '%${q}%' 的方式进行SQL查询语句拼接,导致SQL注入的产生,因为由于使用 ${}语法,传入的参数值会直接插入到SQL查询语句中,未经过任何转义或处理,若其中包括敏感字符、恶意代码,就会导致SQL注入攻击。
解决此问题,可以采用 '%#{q}%' ,#{}语法会将传入的参数值作为预编译参数进行处理,对敏感字符进行转义,安全代码如下:
// 安全代码,采用concat
@Select("select * from users where user like concat('%',#{q},'%')")
List<User> search(String q);
也可以采取强制类型的方案进行修复,使其只能传入指定类型的值:
@Select("select * from users where id = ${id}")
List<User> queryById2(@Param("id") Integer id);
(2) order by注入:
order by注入产生的本质依然是 ${}语法的不当使用。
观察下图代码,调用了 userMapper接口中的 order by 方法,并传入参数 field 和 sort:
userMapper 是一个接口,通常是由 MyBatis 生成的,这个接口定义了与数据库进行交互的方法。userMapper接口中 order by 方法的实现通常在 MyBatis 的XML映射文件或注解中定义。
order by方法在 XML映射文件中的定义如下所示:
定义采用 ${} 语法,若 field = id; drop table users --,sort = asc,语句拼接就会组成恶意代码:
select * from users order by id;drop table users-- asc
同理,order by 方法在注解中的定义若使用了 ${}语法,同样也会产生SQL注入问题:
解决此问题,可以采用排序映射的方法:
<select id="orderBySafe" resultType="com.best.hello.entity.User">
select * from users
<choose>
<when test="field == 'id'">
order by id desc
</when>
<when test="field == 'user'">
order by user desc
</when>
<otherwise>
order by id desc
</otherwise>
</choose>
</select>
用户可输入的值只有 id 和 user两个,有效防止了SQL注入。
(二) 文件上传漏洞:
全局搜索 @RequestMapping("/UPLOAD") 寻找文件上传接口:
发现代码中未对上传文件后缀名做任何校验,导致用户可以上传任意文件,如 .php、.jsp等。
可以使用白名单对上传文件的后缀名进行规范:
// 对上传文件后缀名做白名单处理
public String singleFileUploadSafe(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
try {
byte[] bytes = file.getBytes();
String fileName = file.getOriginalFilename();
Path dir = Paths.get(UPLOADED_FOLDER);
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
// 获取文件后缀名
String Suffix = fileName.substring(fileName.lastIndexOf("."));
// 后缀名白名单
String[] SuffixSafe = {".jpg", ".png", ".jpeg", ".gif", ".bmp", ".ico"};
boolean flag = false;
// 校验后缀名
for (String s : SuffixSafe) {
if (Suffix.toLowerCase().equals(s)) {
flag = true;
break;
}
}
if (!flag) {
return "只允许上传图片,[.jpg, .png, .jpeg, .gif, .bmp, .ico]";
}
(三) 目录穿越 -> 任意文件读取/下载:
未对用户可控的 filename 的参数值进行过滤,导致使用 ../ 进行目录穿越,从而造成任意文件下载/读取:
目录穿越读取日志信息:
可以通过过滤 /字符 和 ..等非法字符的方式防止目录穿越:
// 过滤..和/ ,可以防止遍历操作
public String safe(String filename) {
if (!Security.checkTraversal(filename)) { //对非法字符进行过滤
String filePath = System.getProperty("user.dir") + "/logs/" + filename;
return "安全路径:" + filePath;
} else {
return "检测到非法遍历";
}
}
public static boolean checkTraversal(String content) {
return content.contains("..") || content.contains("/");
}
(四) XSS:
(1) 反射型XSS:
未对用户输入的内容进行字符转义与过滤处理,导致解析恶意JS代码,造成XSS攻击
防御手段有很多种:
1、使用 Spring自带的方法对特殊字符进行转义:
// 采用Spring自带的方法会对特殊字符全转义
import org.springframework.web.util.HtmlUtils;
@GetMapping("/safe1")
public static String safe1(String content) {
return HtmlUtils.htmlEscape(content);
}
2、采用OWASP Java Encoder会对特殊字符全转义:
import org.owasp.encoder.Encode;
public static String safe5(String content){
return Encode.forHtml(content);
}
3、使用ESAPI.encoder().encodeForHTML(content)方法对content中的特殊字符进行转义:
// ESAPI 是一个免费、开源的、网页应用程序安全控件库,它使程序员能够更容易写出更低风险的程序
// 官网:https://owasp.org/www-project-enterprise-security-api/
import org.owasp.esapi.ESAPI;
public static String safe4(String content){
return ESAPI.encoder().encodeForHTML(content);
}
对敏感字符进行转义后如下图所示:
4、富文本场景下使用黑白名单的方式,严格规范标签的使用,防止解析恶意JS代码:
// 场景:针对富文本的处理方式,需保留部分标签
import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;
public static String safe3(String content) {
Safelist whitelist = (new Safelist())
.addTags("p", "hr", "div", "img", "span", "textarea") // 设置允许的标签
.addAttributes("a", "href", "title") // 设置标签允许的属性, 避免如nmouseover属性
.addProtocols("img", "src", "http", "https") // img的src属性只允许http和https开头
.addProtocols("a", "href", "http", "https");
return Jsoup.clean(content, whitelist);
}
(2) 存储型XSS:
论坛、社区等评论区等场景,未对用户输入的内容 content参数进行转义过滤,直接add添加,导致攻击者输入的恶意JS代码被页面解析,产生XSS漏洞。
修复本质上也是对输入的敏感字符进行转义处理:
1、使用org.springframework.web.util.HtmlUtils工具类中的 HtmlUtils.htmlEscape()方法对字符进行转义:
public String safeStore(HttpServletRequest request) {
String content = request.getParameter("content");
String safe_content = HtmlUtils.htmlEscape(content);
xssMapper.add(safe_content);
return "success";
}
2、前端输出转义:
$('#xssTableSafe tbody').append('<tr><td>' + item.id + '</td><td>' + $('<div/>').text(item.content).html() + '</td></tr>');
(五) SSRF漏洞:
(1) 未作任何限制的 SSRF漏洞:
未对用户可控的url参数做任何形式的限制和过滤,导致攻击者可以直接请求内网,以及利用file等伪协议读取敏感信息:
使用 file协议访问任意文件:
访问内网:
通常会采用白名单的方式进行修复,禁止攻击者使用除 HTTP/HTTPS协议之外的其他协议,并且禁止其访问内网:
public String URLConnection3(String url) {
if (!Security.isHttp(url)) {
return "不允许非http/https协议!!!";
} else if (!Security.isWhite(url)) {
return "非可信域名!";
} else {
return HttpClientUtil.URLConnection(url);
}
}
但是这种白名单防御可以通过302跳转等方式进行绕过,所以更好的防御代码如下所示:
public String HTTPURLConnection(String url) {
// 校验 url 是否以 http 或 https 开头
if (!Security.isHttp(url)) {
log.error("[HTTPURLConnection] 非法的 url 协议:" + url);
return "不允许非http/https协议!!!";
}
// 解析 url 为 IP 地址
String ip = Security.urltoIp(url);
log.info("[HTTPURLConnection] SSRF解析IP:" + ip);
// 校验 IP 是否为内网地址
if (Security.isIntranet(ip)) {
log.error("[HTTPURLConnection] 不允许访问内网:" + ip);
return "不允许访问内网!!!";
}
try {
return HttpClientUtils.HTTPURLConnection(url);
} catch (Exception e) {
log.error("[HTTPURLConnection] 访问失败:" + e.getMessage());
return "访问失败,请稍后再试!!!";
}
}
// 1. 判断是否为http协议
public static boolean isHttp(String url) {
return url.startsWith("http://") || url.startsWith("https://");
}
// 2. 解析IP地址
public static String urltoIp(String url) {
try {
URI uri = new URI(url);
String host = uri.getHost().toLowerCase();
InetAddress ip = Inet4Address.getByName(host);
return ip.getHostAddress();
} catch (Exception e) {
return "127.0.0.1";
}
}
// 3. 判断是否为内网IP
public static boolean isIntranet(String url) {
Pattern reg = Pattern.compile("^(127\\.0\\.0\\.1)|(localhost)|^(10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|^(172\\.((1[6-9])|(2\\d)|(3[01]))\\.\\d{1,3}\\.\\d{1,3})|^(192\\.168\\.\\d{1,3}\\.\\d{1,3})$");
Matcher match = reg.matcher(url);
Boolean a = match.find();
return a;
}
// 4. 不允许302跳转
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setInstanceFollowRedirects(false); // 不允许重定向或者对重定向后的地址做二次判断
conn.connect();
}
(六)RCE(远程代码执行):
(1) ProcessBuilder方式导致RCE
对攻击者输入未作过滤,攻击者使用管道符进行RCE:
正常输入:filepath = "/path/to/file"
执行命令:sh -c "ls -l /path/to/file"
管道符拼接后:filepath = "/path/to/file; whoami"
执行命令:sh -c "ls -l /path/to/file; whoami"
可以采用黑名单的方式进行修复,将管道符全部过滤:
public static boolean checkOs(String content) {
String[] black_list = {"|", ",", "&", "&&", ";", "||"};
for (String s : black_list) {
if (content.contains(s)) {
return true;
}
}
return false;
}
(2) Runtime.getRuntime().exec(); 的不当使用导致RCE:
Runtime.getRuntime().exec(cmd)中,会执行cmd参数中的命令,若cmd可控且未进行过滤处理,回导致RCE。
cmd /c start calc 命令弹出计算器:
可以通过设置白名单的方式,严格过滤用户输入的命令,防止RCE:
// 使用白名单替换黑名单。黑名单需要不断更新,而白名单只需要指定允许执行的命令,更容易维护。
public static String safe(String cmd) {
// 定义命令白名单
Set<String> commands = new HashSet<\>();
commands.add("ls");
commands.add("pwd");
// 检查用户提供的命令是否在白名单中
String command = cmd.split("\\s+")[0];
if (!commands.contains(command)) {
return "命令不在白名单中";
}
...
}
用户只允许输入并执行白名单中指定的命令,禁止恶意命令。
(3) ProcessImpl类中的start()方法造成RCE:
ProcessImpl 是更为底层的实现,Runtime和ProcessBuilder执行命令实际上也是调用了ProcessImpl这个类,ProcessImpl 类是一个抽象类不能直接调用,但可以通过反射来间接调用ProcessImpl来达到执行命令的目的。
但代码中未对 cmd参数值进行过滤操作,导致可能会执行恶意代码造成RCE。修复方式同上,采用白名单对用户输入的值进行严格限制。
(4) 脚本引擎(ScriptEngine)代码注入:
load()函数用户从指定的URL处加载并执行 Javascript 脚本,若 某URL-> http://hacker.com/xxx.js 中的JS代码为恶意代码,被 eval()函数执行后,造成RCE。
可以采用白名单的方式进行修复,先验证用户输入的 URL 是否在白名单中,若在,则加载JS代码,若不在,抛出异常:
private static final Pattern ALLOWED_URL_PATTERN = Pattern.compile("^https?://(localhost|127\\.0\\.0\\.1|example\\.com)/.*$");
public void jsEngine(String url) throws Exception {
// 验证 URL 是否可信
if (!ALLOWED_URL_PATTERN.matcher(url).matches()) {
throw new IllegalArgumentException("Invalid URL: " + url);
}
(5) Groovy使用不当造成RCE:
使用 GroovyShell中的 evaluate()方法进行命令执行,本质上依然是未对 cmd参数进行过滤操作,同理采用白名单的方式进行修复即可。
(七) Java反序列化漏洞:
(1) 重写ObjectInputStream对象的readObject()方法不当造成反序列化漏洞:
许多类在实现 Serializable 接口时,会对 readObject()方法进行重写来执行自定义的反序列化逻辑。比如攻击者构造了一个类名为 MaliciousClass,在这个类中,攻击者对 readObject()方法进行了重写,重写的 readObject方法中会执行恶意代码。当 MaliciousClass类被反序列化时,类中的 readObject()方法被调用,导致恶意代码的执行。
import java.io.*;
public class MaliciousClass implements Serializable {
private static final long serialVersionUID = 1L;
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// 恶意代码
Runtime.getRuntime().exec("rm -rf /");
}
}
反序列化目标的值用户可控,导致可以对任意类进行反序列化操作,攻击者构造一个恶意类进行反序列化,就可以实现RCE。
可以使用限定用户只能对指定类进行反序列化的方式来预防:
// 使用Apache Commons IO的ValidatingObjectInputStream,accept方法来实现反序列化类白/黑名单控制
public String safe(String base64) {
try {
base64 = base64.replace(" ", "+");
byte[] bytes = Base64.getDecoder().decode(base64);
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
ValidatingObjectInputStream ois = new ValidatingObjectInputStream(stream);
// 只允许反序列化Student class
ois.accept(Student.class);
ois.readObject();
return "ValidatingObjectInputStream";
} catch (Exception e) {
return e.toString();
}
通过黑/白名单的方式,只允许反序列化 Student 等合法类。
(2) yaml.load()使用不当造成反序列化
org.yaml.snakeyaml.Yaml 为 SnakeYAML的主类,用于解析和生成YAML格式的文档。类SnakeYAML中的load方法会将 YAML文档中的数据反序列化为 Java对象,若 YAML 文档中的内容包含恶意构造的数据,则会造成反序列化漏洞。
未对 yaml.load()函数的 content参数进行严格的过滤,导致产生反序列化漏洞。
可以使用 SafeConstructor来进行防御。SafeConstructor 是 SnakeYAML 提供的一个安全的构造器类,它限制了可以反序列化的类。默认情况下,SafeConstructor 只允许反序列化基本类型(如字符串、数字、布尔值)、集合类型(如列表和映射)以及其他一些安全的类。这样可以防止攻击者通过恶意构造的 YAML 数据来执行任意代码。
// SafeConstructor 是 SnakeYaml 提供的一个安全的构造器。它可以用来构造安全的对象,避免反序列化漏洞的发生。
public void safe(String content) {
Yaml y = new Yaml(new SafeConstructor());
y.load(content);
log.info("[safe] SnakeYaml反序列化: " + content);
}
SafeConstructor只允许反序列化一些基本类型的类,和一些自定义添加的安全类。添加自定义的安全类,比如Student类,代码如下所示:
public class CustomSafeConstructor extends SafeConstructor {
public CustomSafeConstructor() {
this.yamlConstructors.put(new Tag("!student"), new ConstructStudent());
}
private class ConstructStudent extends AbstractConstruct {
@Override
public Object construct(Node node) {
Map<String, Object> values = (Map<String, Object>) constructMapping(node);
String name = (String) values.get("name");
int age = (int) values.get("age");
return new Student(name, age);
}
}
}
public class Student {
xxxxxxxxx //get、set方法;name、age参数等
}
(3) XMLDecoder解析XML文件造成反序列化漏洞:
XMLDecoder中的readObject方法在反序列化对象时,会执行XML文件中的恶意代码,导致产生反序列化漏洞,造成RCE。
包含恶意代码的XML文件可以如下所示,调用ProcessBuilder类中的 start()方法来执行恶意代码:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_231" class="java.beans.XMLDecoder">
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>rm</string>
</void>
<void index="1">
<string>-rf</string>
</void>
<void index="2">
<string>/</string>
</void>
</array>
<void method="start"/> //调用 ProcessBuilder类中的 start()方法,实现命令执行
</object>
</java>
(八) XXE漏洞:
漏洞触发点就在XML解析时,因此重点审计XML解析器是否设置了相关的安全属性。
(1) XMLReader (org.xml.sax.XMLReader)
攻击者可以通过构造一个包含恶意外部实体的XML文档,达到任意文件读取、内网端口探测等恶意目的。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "http://dnslog.cn">
]>
<root>&xxe;</root>
修复XXE漏洞,可以规定在使用XML解析器时,禁止使用外部实体:
public String XMLReader(@RequestBody String content) {
try {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
// 修复:禁用外部实体
xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
xmlReader.parse(new InputSource(new StringReader(content)));
return "XMLReader XXE";
} catch (Exception e) {
return e.toString();
}
}
(2) SAXReader (org.dom4j.io.SAXReader):
SAXReader是Apache dom4j库中的一个类,用于解析XML数据。
未禁用外部实体解析导致产生XXE。
(3) SAXBuilder (org.jdom.input.SAXBuilder):
SAXBuilder 是 JDOM 库中的一个类,用于解析 XML 数据。
未禁用外部实体解析导致产生XXE。
(4) DocumentBuilder (DocumentBuilder):
DocumentBuilder 是 Java 的 javax.xml.parsers 包中的一个类,用于解析 XML 文档并将其转换为 DOM 树。
未禁用外部实体解析导致产生XXE。
(5) Unmarshaller (javax.xml.bind.Unmarshaller):
Unmarshaller 是 Java Architecture for XML Binding (JAXB) 的核心类之一,用于将 XML 数据转换为 Java 对象。
未禁用外部实体解析导致产生XXE。
(九) 越权漏洞:
(1) 水平越权
水平越权的产生通常是由于后端未进行权限校验导致的。
可以采用使用 session、token等方式进行防御,简易的防御代码如下所示:
// 判断当前session与要查询的用户是否一致
public String safe(String name, HttpSession session) {
if (session.getAttribute("LoginUser").equals(name)) {
return userMapper.queryByUser(name);
}
}
(4) 垂直越权:
垂直越权的产生是 admin 和 user的权限未作区分,导致普通用户可以向上垂直越权使用管理员的功能:
同理进行权限校验即可:
// 只允许admin用户可以访问管理页面
public String safe(HttpSession session) {
if (session.getAttribute("LoginUser").equals("admin")) {
return "admin";
} else {
return "commons/403";
}
}
(十) 未授权访问:
拦截器中没有对未授权路径进行拦截导致未授权访问:
拦截未授权路径即可。
(十一) JNDI注入:
攻击者可以通过构造特定的 content 参数,利用 JNDI 查找功能来加载远程恶意代码,从而在服务器上执行任意代码。这通常通过 RMI 或 LDAP 协议实现。
可采用白名单的方式进行修复,限制 lookup方法只能查找预定义的、安全的资源:
public String safe2(String content) {
List<String> whiteList = Arrays.asList("java:comp/env/jdbc/mydb", "java:comp/env/mail/mymail");
if (whiteList.contains(content)) {
try {
Context ctx = new InitialContext();
ctx.lookup(content);
} catch (Exception e) {
log.warn("JNDI错误消息");
}
return HtmlUtils.htmlEscape(content); //返回经过转义的 content,也有效防止了XSS攻击
} else {
return "JNDI 白名单拦截";
}
}
(十三) CSRF漏洞:
CSRF漏洞的产生大多是因为未校验 csrf_token 和 Referer头导致。
若对 csrf_token 和 Referer头进行校验,就可以很好的防御CSRF漏洞:
(1) 校验csrf_token:
String token = request.getParameter("csrfToken");
String sessionToken = (String) session.getAttribute("csrfToken");
// 校验CSRF Token
if (!token.equals(sessionToken)) {
result.put("success", false);
result.put("message", "token is not valid");
return result;
}
(2) 校验 Referer头:
String token = request.getParameter("csrfToken");
String sessionToken = (String) session.getAttribute("csrfToken");
// 校验CSRF Token
if (!token.equals(sessionToken)) {
result.put("success", false);
result.put("message", "token is not valid");
return result;
}
(十四) URL重定向漏洞:
利用URL重定向中的被信任域名来钓鱼,关键参数:url、redirectURL、target等。
采用白名单进行防御,只允许跳转到白名单中设置的安全地址:
public static boolean isWhite(String url) {
List<String> url_list = new ArrayList<String>();
url_list.add("baidu.com");
url_list.add("www.baidu.com");
url_list.add("oa.baidu.com");
URI uri = null;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
System.out.print(e);
}
String host = uri.getHost().toLowerCase();
System.out.println(host);
return url_list.contains(host);
}
(十五) DOS(拒绝服务)漏洞:
漏洞代码:
public String vul(String content) {
boolean match = Pattern.matches("(a|aa)+", content);
return String.format("正则匹配:%s,正则表达式拒绝服务攻击", match);
}
安全代码:
public String safe(String content) {
boolean match = com.google.re2j.Pattern.matches("(a|aa)+", content);
return String.format("正则匹配:%s,安全正则表达式", match);
}
若 content的值很长,很复杂,漏洞代码会出现DOS漏洞。
原因:
漏洞代码中进行正则匹配使用的是 Java内置的正则表达式引擎->java.util.regex.Pattern。在处理某些特定的输入时,可能会导致指数级的时间复杂度,从而引发 ReDoS 攻击。例如,对于正则表达式 (a|aa)+,输入 aaaaaaaaaaaaaaaaaaaaaaa! 会导致引擎花费大量时间进行匹配。
而安全代码中则使用了 RE2 正则表达式引擎->com.google.re2j.Pattern。设计上避免了回溯,因此在处理复杂正则表达式时具有线性的时间复杂度->O(n),不会引发 ReDoS 攻击。
(十六) Swagger未授权访问:
修复很简单->限制访问环境即可:
@Configuration
@EnableSwagger2
// 设置swagger只能在dev和test环境可访问
@Profile({"dev", "test"})
public class Swagger2Config {
}
标签:return,String,url,public,content,Sec,Java,序列化,Hello
From: https://www.cnblogs.com/kgty/p/18452324