XSS攻击是跨站脚本攻击,又分存储型和反射型。存储型XSS攻击,就是将攻击脚本存储至数据库,以致所有访问者都会受到攻击。攻击脚本一般会将用户的cookie发送给攻击者,然后攻击者伪造用户登陆。反射型XSS攻击,就是攻击者通过特定的方式(邮件等)发送给用户恶意链接,通过用户点击达到攻击目的。
示例脚本:1'"><img src=x onerror=alert(1)>
如何防止储存型XSS攻击?
JAVA端配置XssFilter:
package com.lyh.util;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.lang3.StringEscapeUtils;
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>
* getHeaderNames 也可能需要覆盖
*/
@Override
public String getHeader(String name) {
return StringEscapeUtils.escapeHtml4(super.getHeader(name));
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public String getParameter(String name) {
return StringEscapeUtils.escapeHtml4(super.getParameter(name));
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values == null || values.length == 0) {
return values;
}
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++) {
escapseValues[i] = StringEscapeUtils.escapeHtml4(values[i]);
}
return escapseValues;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = super.getParameterMap();
if (map == null || map.size() == 0) {
return map;
}
Set<Entry<String, String[]>> set = map.entrySet();
for (Entry<String, String[]> entry : set) {
String[] values = entry.getValue();
for (int i = 0; values != null && i < values.length; i++) {
values[i] = StringEscapeUtils.escapeHtml4(values[i]);
}
}
return map;
}
@Override
public String getQueryString() {
return StringEscapeUtils.escapeHtml4(super.getQueryString());
}
}
package com.lyh.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;
import javax.servlet.http.HttpServletResponse;
import com.lyh.util.XssHttpServletRequestWrapper;
/**
* html浏览器端不缓存,防止XSS跨站脚本攻击、防止跨帧脚本编制攻击(禁止被iFrame引用)
*/
public class XssSecurityFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Expose-Headers", "*");
chain.doFilter(new XssHttpServletRequestWrapper(request), response);
}
@Override
public void destroy() {
}
}
package com.lyh.config;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.boot.web.servlet.ErrorPageRegistrar;
import org.springframework.boot.web.servlet.ErrorPageRegistry;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import com.lyh.filter.ReSubmitFilter;
import com.lyh.filter.XssSecurityFilter;
/**
* 2017/3/10.
*/
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean indexXssSecurityFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean(new XssSecurityFilter());
registration.addUrlPatterns("/*");
registration.setName("xssSecurityFilter");
registration.setOrder(9);
return registration;
}
@Bean
public FilterRegistrationBean reSubmitFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean(new ReSubmitFilter());
registration.addUrlPatterns("/*");
registration.setName("reSubmitFilter");
registration.setOrder(10);
return registration;
}
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许请求发送Cookie
corsConfiguration.setAllowCredentials(Boolean.TRUE);
// 原始请求的域名
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
// 添加请求头字段
corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
// 服务器支持的所有跨域请求的方法
corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
// 预检请求的有效期,单位为秒。
corsConfiguration.setMaxAge(3600L);
return corsConfiguration;
}
/**
* 跨域过滤器
*
* @return
*/
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
CorsFilter corsFilter = new CorsFilter(source);
return new FilterRegistrationBean(corsFilter);
}
@Bean
public ErrorPageRegistrar errorPageRegistrar(){
return new MyErrorPageRegistrar();
}
private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/404"));
}
}
}
前端将value中的html标签转义
var escapeHTML = function (text) {
if (typeof text === 'string') {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/`/g, '`');
}
return text;
};
来源:oschina
链接:https://my.oschina.net/leeyouhui/blog/3215510