前言:
1.XSS简介
跨站脚本(cross site script)简称为XSS,是一种经常出现在web应用中的计算机安全漏洞,也是web中最主流的攻击方式。
XSS是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而添加一些代码,嵌入到web页面中去,使别的用户访问都会执行相应的嵌入代码。
1.1.XSS攻击的危害
1、盗取用户资料,比如:登录帐号、网银帐号等
2、利用用户身份,读取、篡改、添加、删除企业敏感数据等
3、盗窃企业重要的具有商业价值的资料
4、非法转账
5、强制发送电子邮件
6、网站挂马
7、控制受害者机器向其它网站发起攻击
1.2.防止XSS解决方案
XSS的根源主要是没完全过滤客户端提交的数据 ,所以重点是要过滤用户提交的信息。
将重要的cookie标记为http only, 这样的话js 中的document.cookie语句就不能获取到cookie了.
只允许用户输入我们期望的数据。 例如:age用户年龄只允许用户输入数字,而数字之外的字符都过滤掉。
对数据进行Html Encode 处理: 用户将数据提交上来的时候进行HTML编码,将相应的符号转换为实体名称再进行下一步的处理。
过滤或移除特殊的Html标签, 例如:
2.1SQL注入的危害
1.数据库信息泄漏:数据库中存放的用户的隐私信息的泄露。
2. 网页篡改:通过操作数据库对特定网页进行篡改。
3. 数据库被恶意操作:数据库服务器被攻击
4. 服务器被远程控制,被安装后门
5. 删除和修改数据库信息
2.2.防止SQL注入的方式
通常情况下,SQL注入的位置包括:
(1)表单提交,主要是POST请求,也包括GET请求;
(2)URL参数提交,主要为GET请求参数;
(3)Cookie参数提交;
(4)HTTP请求头部的一些可修改的值,比如Referer、User_Agent等;
2.3.防止SQL注入的解决方案
(1)对用户的输入进行校验,使用正则表达式过滤传入的参数
(2)使用参数化语句,不要拼接sql,也可以使用安全的存储过程
(3)不要使用管理员权限的数据库连接,为每个应用使用权限有限的数据库连接
(4)检查数据存储类型
(5)重要的信息一定要加密
项目以SpringBoot项目为例的代码示例:
XssFilter:
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
@Compent
public class XssFilter implements Filter {
FilterConfig filterConfig = null;
private List urlExclusion = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String servletPath = httpServletRequest.getServletPath();
if (urlExclusion != null && urlExclusion.contains(servletPath)) {
chain.doFilter(request, response);
} else {
chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
}
}
public List getUrlExclusion() {
return urlExclusion;
}
public void setUrlExclusion(List urlExclusion) {
this.urlExclusion = urlExclusion;
}
}
XssHttpServletRequestWrapper:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}
private String cleanXSS(String value) {
//You'll need to remove the spaces from the html entities below
value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
value = value.replaceAll("'", "& #39;");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
return value;
}
}
以上是其配置,在其拦截器或者过滤器对于某个请求进行Xss 和 Sql注入避免的操作:
GetRequest:
/**
* 获取包装防Xss Sql注入的 HttpServletRequest
* @return request
*/
public static HttpServletRequest getRequest() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return new WafRequestWrapper(request);
}
WafRequestWrapper:
public class WafRequestWrapper extends HttpServletRequestWrapper {
private boolean filterXSS = true;
private boolean filterSQL = true;
public WafRequestWrapper(HttpServletRequest request, boolean filterXSS, boolean filterSQL) {
super(request);
this.filterXSS = filterXSS;
this.filterSQL = filterSQL;
}
public WafRequestWrapper(HttpServletRequest request) {
this(request, true, true);
}
/**
* @Description 数组参数过滤
* @param parameter
* 过滤参数
* @return
*/
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if ( values == null ) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for ( int i = 0 ; i < count ; i++ ) {
encodedValues[i] = filterParamString(values[i]);
}
return encodedValues;
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public Map getParameterMap() {
Map primary = super.getParameterMap();
Map result = new HashMap(primary.size());
for ( Map.Entry entry : primary.entrySet() ) {
result.put(entry.getKey(), filterEntryString(entry.getValue()));
}
return result;
}
protected String[] filterEntryString(String[] rawValue) {
for ( int i = 0 ; i < rawValue.length ; i++ ) {
rawValue[i] = filterParamString(rawValue[i]);
}
return rawValue;
}
/**
* @Description 参数过滤
* @param parameter
* 过滤参数
* @return
*/
@Override
public String getParameter(String parameter) {
return filterParamString(super.getParameter(parameter));
}
/**
* @Description 请求头过滤
* @param name
* 过滤内容
* @return
*/
@Override
public String getHeader(String name) {
return filterParamString(super.getHeader(name));
}
/**
* @Description Cookie内容过滤
* @return
*/
@Override
public Cookie[] getCookies() {
Cookie[] existingCookies = super.getCookies();
if (existingCookies != null) {
for (int i = 0 ; i < existingCookies.length ; ++i) {
Cookie cookie = existingCookies[i];
cookie.setValue(filterParamString(cookie.getValue()));
}
}
return existingCookies;
}
/**
* @Description 过滤字符串内容
* @param rawValue
* 待处理内容
* @return
*/
protected String filterParamString(String rawValue) {
if (null == rawValue) {
return null;
}
String tmpStr = rawValue;
if (this.filterXSS) {
tmpStr = stripXSS(rawValue);
}
if (this.filterSQL) {
tmpStr = stripSqlInjection(tmpStr);
}
return tmpStr;
}
/**
* @Description 过滤XSS脚本内容
* @param value
* 待处理内容
* @return
*/
public static String stripXSS(String value) {
String rlt = null;
if (null != value) {
// 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
rlt = value.replaceAll("", "");
// Avoid anything between script tags
Pattern scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Avoid anything in a src='...' type of expression
/*scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
rlt = scriptPattern.matcher(rlt).replaceAll("");
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
rlt = scriptPattern.matcher(rlt).replaceAll("");*/
// Remove any lonesome tag
scriptPattern = Pattern.compile("", Pattern.CASE_INSENSITIVE);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Remove any lonesome