抵御即跨站脚本(XSS)攻击
Posted 一菜一汤
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了抵御即跨站脚本(XSS)攻击相关的知识,希望对你有一定的参考价值。
1、问题描述
什么是XSS?
- 通过网页代码的漏洞,注入恶意指令到网页,当用户加载并执行攻击者恶意制造的网络程序,通常是javascript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的html
- 攻击者可以通过这种方式获取到一些私密权限,token,cookie等重要信息,冒充客户登录
- 例如用户在发帖或者注册的时候,在文本框中输入 ,这段代码 如果不经过转义处理,而直接保存到数据库。将来视图层渲染HTML的时候,把这段代码输出到 页面上,那么
如何让避免这种XSS攻击
对用户输入信息进行转义(Hutool工具包为我们提供了HtmlUtil可以解决此类问题)
2、代码
问题?
- 如何去转义用户输入信息
- 过滤器,可以继承于HttpServletRequest的接口
- 但是由于这个接口定义的方法太多,一一实现比较麻烦,因此我们有更好的选择
- 过滤器,可以继承于HttpServletRequest的接口
- 更好的选择
- 自定义请求类的方式
- 继承HttpServletRequestWrapper父类
- 自定义请求类的方式
JavaEE规范还定义 了 HttpServletRequestWrapper ,这个类是请求类的包装类,用上了装饰器模式。不得不说这里 用到的设计模式真的非常棒,无论各家应用服务器厂商怎么去实现 HttpServletRequest 接口, 用户想要自定义请求,只需要继承 HttpServletRequestWrapper ,对应覆盖某个方法即可,然后 把请求传入请求包装类,装饰器模式就会替代请求对象中对应的某个方法。用户的代码和服务器 厂商的代码完全解耦,我们不用关心 HttpServletRequest 接口是怎么实现的,借助于包装类我 们可以随意修改请求中的方法。
上代码
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if(!StrUtil.hasEmpty(value)){
value = HtmlUtil.filter(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if(ArrayUtil.isNotEmpty(values)){
for (int i = 0; i < values.length; i++) {
String value =values[i];
if(!StrUtil.hasEmpty(values[i])){
value = HtmlUtil.filter(value);
}
values[i] = value;
}
}
return values;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> parameterMap = super.getParameterMap();
LinkedHashMap<String, String[]> map = new LinkedHashMap<>();
if(CollUtil.isNotEmpty(parameterMap)){
for (String key: parameterMap.keySet()) {
String[] values = parameterMap.get(key);
if(ArrayUtil.isNotEmpty(values)){
for (int i = 0; i < values.length; i++) {
String value =values[i];
if(!StrUtil.hasEmpty(values[i])){
value = HtmlUtil.filter(value);
}
values[i] = value;
}
}
map.put(key,values);
}
}
return map;
}
@Override
public String getHeader(String name) {
String header = super.getHeader(name);
if(StrUtil.isNotBlank(header)){
header = HtmlUtil.filter(header);
}
return header;
}
@Override
public ServletInputStream getInputStream() throws IOException {
InputStream in = super.getInputStream();
StringBuffer body = new StringBuffer();
InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
BufferedReader buffer = new BufferedReader(reader);
String line = buffer.readLine();
while (line != null) {
body.append(line);
line = buffer.readLine();
}
buffer.close();
reader.close();
in.close();
Map<String, Object> map = JSONUtil.parseObj(body.toString());
Map<String, Object> resultMap = new HashMap(map.size());
for (String key : map.keySet()) {
Object val = map.get(key);
if (map.get(key) instanceof String) {
resultMap.put(key, HtmlUtil.filter(val.toString()));
} else {
resultMap.put(key, val);
}
}
String str = JSONUtil.toJsonStr(resultMap);
final ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes());
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bain.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
}
自定义过滤器
为了让刚刚定义的包装类生效,我们还要在 com.example.emos.wx.config.xss 中创建 XssFilter 过滤器。过滤器拦截所有请求,然后把请求传入包装类,这样包装类就能覆盖所有请 求的参数方法,用户从请求中获得数据,全都经过转义。
@WebFilter(urlPatterns = "/*") //过滤所有请求路径
public class XssFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
XssHttpServletRequestWrapper servletRequestWrapper = new XssHttpServletRequestWrapper(
(HttpServletRequest) servletRequest);
filterChain.doFilter(servletRequestWrapper,servletResponse);
}
@Override
public void destroy() {
}
}
给主启动类添加@ServletComponentScan注解
以上是关于抵御即跨站脚本(XSS)攻击的主要内容,如果未能解决你的问题,请参考以下文章