1、检测到目标URL存在宽字节跨站漏洞
2、检测到目标URL存在框架注入漏洞
3、检测到目标URL存在链接注入漏洞
已上三点的解决方案主要是给项目配置过滤器,将URL中的特殊字符过滤掉
CookieHttpOnlyFilter.java文件
package com.zysj.boss.web.filter;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 功能描述:
* <p>
* 1.Cookie 设置 httpOnly属性 Cookie
* 2.设置 httpOnly属性防止js读取cookie
* </p>
*
* @author steven
*/
public class CookieHttpOnlyFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) {
chain.doFilter(request, response);
return;
}
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpResp = (HttpServletResponse) response;
Cookie[] cookies = httpReq.getCookies();
if (cookies != null) {
Cookie cookie = cookies[0];
if (cookie != null) {
HttpSession session = httpReq.getSession();
if (session != null) {
String sessionId = session.getId();
// http设置
// httpResp.addHeader("Set-Cookie", "JSESSIONID=" + sessionId + "; Path=/fis; HttpOnly");
// httpResp.addHeader("x-frame-options","SAMEORIGIN");
// https设置
httpResp.addHeader("Set-Cookie", "JSESSIONID=" + sessionId
+ "; Path=/admin;Secure; HttpOnly");
}
}
}
chain.doFilter(httpReq, httpResp);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
XssAndSqlFilter.java文件
package com.zysj.boss.web.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class XssAndSqlFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
XssAndSqlHttpServletRequestWrapper xssRequest = new XssAndSqlHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
XssAndSqlHttpServletRequestWrapper.java文件
package com.zysj.boss.web.filter;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
HttpServletRequest orgRequest = null;
public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
orgRequest = request;
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss & sql过滤。
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss & sql过滤。
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取 getHeaderNames 也可能需要覆盖
*/
@Override
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
/**
* 将容易引起xss & sql漏洞的半角字符直接替换成全角字符
*
* @param s
* @return
*/
private static String xssEncode(String s) {
if (s == null || s.isEmpty()) {
return s;
} else {
s = stripXSSAndSql(s);
}
StringBuilder sb = new StringBuilder(s.length() + 16);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '>':
sb.append(">");// 转义大于号
break;
case '<':
sb.append("<");// 转义小于号
break;
case '\'':
sb.append("'");// 转义单引号
break;
case '\"':
sb.append(""");// 转义双引号
break;
case '&':
sb.append("&");// 转义&
break;
case '#':
sb.append("#");// 转义#
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
}
/**
* 获取最原始的request
*
* @return
*/
public HttpServletRequest getOrgRequest() {
return orgRequest;
}
/**
* 获取最原始的request的静态方法
*
* @return
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
if (req instanceof XssAndSqlHttpServletRequestWrapper) {
return ((XssAndSqlHttpServletRequestWrapper) req).getOrgRequest();
}
return req;
}
/**
* 防止xss跨脚本攻击(替换,根据实际情况调整)
*/
public static String stripXSSAndSql(String value) {
if (value != null) {
// NOTE: It's highly recommended to use the ESAPI library and
// uncomment the following line to
// avoid encoded attacks.
// value = ESAPI.encoder().canonicalize(value);
// Avoid null characters
/** value = value.replaceAll("", ""); ***/
// Avoid anything between script tags
Pattern scriptPattern = Pattern
.compile(
"<[\r\n| | ]*script[\r\n| | ]*>(.*?)</[\r\n| | ]*script[\r\n| | ]*>",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything in a
// src="http://www.yihaomen.com/article/java/..." type of
// e-xpression
scriptPattern = Pattern.compile(
"src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome </script> tag
scriptPattern = Pattern.compile("</[\r\n| | ]*script[\r\n| | ]*>",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome <script ...> tag
scriptPattern = Pattern.compile("<[\r\n| | ]*script(.*?)>",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid eval(...) expressions
scriptPattern = Pattern.compile("eval\\((.*?)\\)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid e-xpression(...) expressions
scriptPattern = Pattern.compile("e-xpression\\((.*?)\\)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid javascript:... expressions
scriptPattern = Pattern.compile(
"javascript[\r\n| | ]*:[\r\n| | ]*",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid vbscript:... expressions
scriptPattern = Pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*",
Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid onload= expressions
scriptPattern = Pattern.compile("onload(.*?)=",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
| Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
}
return value;
}
}
在web.xml文件中引用一下
<filter>
<filter-name> CookieHttpOnly</filter-name>
<filter-class>xxx.xxx.filter.CookieHttpOnlyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name> CookieHttpOnly</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 解决xss & sql漏洞 -->
<filter>
<filter-name>xssAndSqlFilter</filter-name>
<filter-class>xxx.xxx.filter.XssAndSqlFilter</filter-class>
</filter>
<!-- 解决xss & sql漏洞 -->
<filter-mapping>
<filter-name>xssAndSqlFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
4、Spring Boot Actuator未授权访问
修改spring boot的配置文件 Spring boot 关闭Actuator
在bootstrap.yml中
management:
server:
port: -1 # 修改端口,跳过安全漏洞扫描
endpoints:
enabled-by-default: false #关闭监控
5、jQuery 存在 XSS 漏洞
该问题是由于项目中用的jQuery版本太低的问题,升级Jquery版本为3.6.1,因为升级之后的版本不兼容之前的版本,需要引入JQuery提供的jQuery Migrate v3.4.0
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/jquery-migrate-3.4.0.min.js"></script>
但是其中还会存在一些兼容性问题,在引入之后引入一些改写的方法
/**
* jQuery.browser | jQuery API Documentation该属性已经在1.9版本中删除,为了兼容老代码
*/
(function () {
/**
* 注意,以下代码,应确保 引用在 jquery 3.6.1, jquery-migrate-3.4.0.min.js,以及 jquery-ui-1.8.10.custom.min.js 等内容之后,否则
* 相关的 代码托管 可能会被取代 而 无效。
*/
jQuery.curCSS = function (element, prop, val) {
return jQuery(element).css(prop, val);
};
/**
* James add on 2022.11.24 , 相关代码摘录自 jquery 1.7.2
* 此 修复是为了 兼容 以下有关写法,在 append 到 jquery 对象里时,能适应 老版本的渲染逻辑。
* $.append("<div><i class='abc' /> <span>ttt</span></div>");
* 上述内容,在 jquery 1.7.2 版本里,会被渲染为:
* <div><i class='abc'></i><span>ttt</span></div>
*
* 而在 jquery 3.6.1 里,则会被渲染为:
* <div><i class='abc'><span>ttt</span></i></div>
*
* 这是由于 在 旧版 jquery 里,针对 非闭合的标签有过特定处理,而在 jquery 3.6.1 里则移除了这个做法。
* 因此直接在 element 的 innterHtml 里面写入 <div><i class='abc' /> <span>ttt</span></div> 这个内容,
* 与 3.6.1 里面是一致的。
*
* 所以根本上是不规范的 html 写法,只是老版本 jquery 做了容错,而新版本没有容错,因而导致问题。
*
*/
var oldAppend = jQuery.fn.append;
jQuery.fn.append = function () {
/**
* 相关素材来自 jquery 1.7.2
*/
var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig;
if (arguments.length > 0
&& typeof (arguments[0]) == "string") {
var elem = arguments[0];
elem = elem.replace(rxhtmlTag, "<$1></$2>");
arguments[0] = elem;
}
return oldAppend.apply(this, arguments);
};
var oldOuterWidth = jQuery.fn.outerWidth;
jQuery.fn.outerWidth = function () {
if (arguments.length <= 0) {
arguments[0] = false;
arguments.length = 1;
}
var result = oldOuterWidth.apply(this, arguments);
return result === undefined ? 0 : result;
};
var oldOuterHeight = jQuery.fn.outerHeight;
jQuery.fn.outerHeight = function () {
if (arguments.length <= 0) {
arguments[0] = false;
arguments.length = 1;
}
var result = oldOuterHeight.apply(this, arguments);
return result === undefined ? 0 : result;
};
})();