什么是xss攻击?
XSS攻击是Cross-Site Scripting的缩写,直白来说,就是页面被注入了恶意的代码——用户输入的内容跳出文本的限制,成了可执行的代码。
xss分类
根据入侵代码的来源,通常将XSS攻击分成三类
存储型xss攻击
特点:恶意代码已经落库,被拼接到HTML中返回。
- 攻击者通过论坛评论区提交恶意代码到数据库;
- 其他用户打开论坛,服务端把恶意代码取出来,拼接在HTML中返回;
- 恶意代码在用户的浏览器端运行;
除了论坛,这类攻击还常见于用户私信发送。
<div>
评论内容:<%= getContent("comment") %>
</div>
<div>
评论内容:<script>alert('XSS');</script>
</div>
反射性xss攻击
特点:恶意代码被拼接到URL上,被拼接到HTML中返回。
- 攻击者拼接出包含恶意代码的受害网站URL,诱导用户点击;
- 用户点击该URL,目标网站的服务器取出恶意代码,拼接到HTML返回;
- 恶意代码在其他用户的浏览器端运行;
这类攻击需要用户主动点击受害网站的URL,攻击者会通过通过QQ群或者邮件等方式诱导点击。
比如一个恶意URL可以长这样:http://xxx/search?keyword="<script>alert('XSS');</script>
<div>
你好<%= getParameter("keyword") %>
</div>
<div>
你好<script>alert('XSS');</script>
</div>
dom xss攻击
特点:恶意代码被拼接到URL上,被前端JavaScript代码执行。
- 攻击者拼接出包含恶意代码的受害网站URL,诱导用户点击;
- 用户点击该URL;
- 前端 JavaScript 取出 URL 中的恶意代码,恶意代码在用户的浏览器端运行;
DOM型和反射型的区别在于,DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞。而其他两种 XSS 都属于服务端的安全漏洞。
上述三种XSS攻击的目的都一致:恶意代码在浏览器端运行后,窃取用户的本地存储数据:通过document.cookie获取用户的身份凭证,然后通过网络请求将数据发送给恶意服务器。
接下来就可以进行下一步:冒充用户去对受害网站发起请求完成指定操作,比如转账给攻击者的账户。
漏洞修复
既然xss漏洞是分为三种类型,那么理论上就按照对应类型来修复漏洞就可以了,但是那,仔细对比一下 上面所谓的存储型和反射型,似乎都是经过服务端返回的,那其实只要我们后端返回的时候,校验掉这些错误或者恶意代码就可以了,所以其实就是两种解决方案对应的 三种的漏洞类型。
第一种和第二种漏洞类型修复
其实都是通过filter来实现的,但是有意思的是 你使用filter是有两种方式的
- 直接继承filter类,实现对应的doFilter方法即可,当然要注入到spring容器当中
- 通过@bean来实现,由于springbootweb提供了FilterRegistrationBean,所以直接new一个注入进去即可
继承filter
pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.4</version>
</dependency>
java
XSSFilter
package com.example.scheduledtest;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Component;
@WebFilter
@Component
public class XSSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
XssAndSqlHttpServletRequestWrapper xssRequestWrapper = new XssAndSqlHttpServletRequestWrapper(req);
chain.doFilter(xssRequestWrapper, response);
}
@Override
public void destroy() {
}
/**
* 过滤json类型的
*
* @param builder
* @return
*/
@Bean
@Primary
public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
//解析器
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
//注册xss解析器
SimpleModule xssModule = new SimpleModule("XssStringJsonSerializer");
xssModule.addSerializer(new XssStringJsonSerializer());
objectMapper.registerModule(xssModule);
//返回
return objectMapper;
}
}
XssAndSqlHttpServletRequestWrapper
package com.example.scheduledtest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.util.StringUtils;
public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest request;
public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
if (!StringUtils.isEmpty(value)) {
value = StringEscapeUtils.escapeHtml4(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] parameterValues = super.getParameterValues(name);
if (parameterValues == null) {
return null;
}
for (int i = 0; i < parameterValues.length; i++) {
String value = parameterValues[i];
parameterValues[i] = StringEscapeUtils.escapeHtml4(value);
}
return parameterValues;
}
}
XssStringJsonSerializer
package com.example.scheduledtest;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import org.apache.commons.text.StringEscapeUtils;
public class XssStringJsonSerializer extends JsonSerializer<String> {
@Override
public Class<String> handledType() {
return String.class;
}
@Override
public void serialize(String value, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
if (value != null) {
String encodedValue = StringEscapeUtils.escapeHtml4(value);
jsonGenerator.writeString(encodedValue);
}
}
}
第三种漏洞修复
新建cookie的时候,设置http-only为true就可以了。
cookie.setHttpOnly(true);