详解java解决XSS攻击常用方法总结

网友投稿 435 2023-01-21

详解java解决XSS攻击常用方法总结

前言

在项目验收阶段,通常会对待验收项目做一些安全漏洞的测试,比如接口攻击,并发测试,XSS注入,SQL恶意注入测试,安全越权等操作,这时,就是考验项目的安全方面是否做的足够健壮的时候,本篇对XSS脚本攻击在实际WEB项目中的处理办法,提供2种可实行的方法

xss攻击

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是javascript,但实际上也可以包括java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容

简单说就是说,通过在输入框输入一些js代码,如在账号密码输入框中输入

或者

这样点击提交的时候就会触发alert弹窗,分别弹出 xss 和 @@ 的内容,这里只是做个简单的演示,弹了个窗口,还能存储病毒下载地址到服务端,进入的时候自动下载,或者修改你的cookie啥的,这里感兴趣可以百度查查xss攻击

解决方式一:强制修改html敏感标签内容

这是一种相对容易理解的方式,解决思路就是,当恶意注入的字段中,包含了类似这种html标签时,后台程序代码中强制替换或更改标签内容,这样存入数据库的内容再次返回至页面时,就不会以html的形式进行执行了

下面提供一个工具类

/**

* xss特殊字符拦截与过滤

*

* @author zhangcy

* @date 2021-04016

*/

public class XssStrUtils {

/**

* 滤除content中的危险 HTML 代码, 主要是脚本代码, 滚动字幕代码以及脚本事件处理代码

* @param content 需要滤除的字符串

* @return 过滤的结果

*/

public static String replaceHtmlCode(String content) {

if (null == content) return null;

if (0 == content.length()) return "";

// 需要滤除的脚本事件关键字

String[] eventKeywords = {

"onmouseover", "onmouseout", "onmousedown", "onmouseup", "onmousemove", "onclick", "ondblclick",

"onkeypress", "onkeydown", "onkeyup", "ondragstart", "onerrorupdate", "onhelp", "onreadystatechange",

"onrowenter", "onrowexit", "onselectstart", "onload", "onunload", "onbeforeunload", "onblur",

"onerror", "onfocus", "onresize", "onscroll", "oncontextmenu", "alert"

};

content = replace(content, "

content = replace(content, "

content = replace(content, "

content = replace(content, "

content = replace(content, "'", "_", false);// 将单引号替换成下划线

content = replace(content, "\"", "_", false);// 将双引号替换成下划线

// 滤除脚本事件代码

for (int i = 0; i < eventKeywords.length; i++) {

content = replace(content, eventKeywords[i], "_" + eventKeywords[i], false); // 添加一个"_", 使事件代码无效

}

return content;

}

/**

* 将字符串 source 中的 oldStr 替换为 newStr, 并以大小写敏感方式进行查找

*

* @param source 需要替换的源字符串

* @param oldStr 需要被替换的老字符串

* @param newStr 替换为的新字符串

*/

private static String replace(String source, String oldStr, String newStr) {

return replace(source, oldStr, newStr, true);

}

/**

* 将字符串 source 中的 oldStr 替换为 newStr, matchCase 为是否设置大小写敏感查找

*

* @param source 需要替换的源字符串

* @param oldStr 需要被替换的老字符串

* @param newStr 替换为的新字符串

* @param matchCase 是否需要按照大小写敏感方式查找

*/

private static String replace(String source, String oldStr, String newStr,boolean matchCase) {

if (source == null) return null;

// 首先检查旧字符串是否存在, 不存在就不进行替换

if (source.toLowerCase().indexOf(oldStr.toLowerCase()) == -1) return source;

int findStartPos = 0;

int a = 0;

while (a > -1) {

int b = 0;

String str1, str2, str3, str4, strA, strB;

str1 = source;

str2 = str1.toLowerCase();

str3 = oldStr;

str4 = str3.toLowerCase();

if (matchCase) {

strA = str1;

strB = str3;

} else {

strA = str2;

strB = str4;

}

a = strA.indexOf(strB, findStartPos);

if (a > -1) {

b = oldStr.length();

findStartPos = a + b;

StringBuffer bbuf = new StringBuffer(source);

source = bbuf.replace(a, a + b, newStr) + "";

// 新的查找开始点位于替换后的字符串的结尾

findStartPos = findStartPos + newStr.length() - b;

}

}

return source;

}

}

我们用一个实际的接口做一下简单的测试

@PostMapping("/getAccName")

public String getAccName(@RequestBody NameParams params){

String s = XssStrUtils.replaceHtmlCode(params.getName());

return s;

}

使用接口工具调一下,

使用这种方式,即使前端恶意注入了某些非法的html标签,经过后端的过滤处理,返回的内容就不会执行html的相关操作事件了

解决方式二:利用过滤器过滤非法html标签

第二种思路,考虑在过滤器中添加对所有请求接口的参数进行参数的拦截过滤,即程序认为的不合法标签都会自动做过滤,至于过滤的规则,可以借助现有的第三方组件,比如spring框架的htmlUtil类,这里使用hutool工具集提供的相关API做处理

导入依赖

cn.hutool

hutool-all

5.5.9

1、添加自定义过滤器增强包装类

public class XssHttpRequestWrapper extends HttpServletRequestWrapper {

public XssHttpRequestWrapper(HttpServletRequest request) {

super(request);

}

@Override

public String getParameter(String name) {

String value = super.getParameter(name);

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

return value;

}

@Override

public String[] getParameterValues(String name) {

String[] values = super.getParameterValues(name);

if(values!=null){

for(int i=0;i

String value = values[i];

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

values[i]=value;

}

}

return values;

}

@Override

public Map getParameterMap() {

Map parameters = super.getParameterMap();

Map map = new LinkedHashMap<>();

if(parameters !=null){

for(String key : parameters.keySet()){

String[] values = parameters.get(key);

for(int i=0;i

String value = values[i];

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

values[i]=value;

}

map.put(key,values);

}

}

return map;

}

@Override

public String getHeader(String name) {

String value = super.getHeader(name);

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

return value;

}

@Override

public ServletInputStream getInputStream() throws IOException {

InputStream in = super.getInputStream();

InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));

BufferedReader buffer = new BufferedReader(reader);

StringBuffer body = new StringBuffer();

String line = buffer.readLine();

while (line !=null){

body.append(line);

line = buffer.readLine();

}

buffer.close();

reader.close();

in.close();

Map map = JSONUtil.parseObj(body.toString());

Map result = new LinkedHashMap<>();

for(String key : map.keySet()){

Object val = map.get(key);

if(val instanceof String){

if(!StringUtils.isEmpty(val.toString())){

result.put(key,HtmlUtil.filter(val.toString()));

}

}else {

result.put(key,val);

}

}

String json = JSONUtil.toJsonStr(result);

ByteArrayInputStream bain = new ByteArrayInputStream(json.getBytes());

return new ServletInputStream() {

@Override

public boolean isFinished() {

return false;

}

@Override

public boolean isReady() {

return false;

}

@Override

public void setReadListener(ReadListener readListener) {

}

@Override

public int read() throws IOException {

return bain.read();

}

};

}

}

可以理解为,在自定义过滤器中添加上面的增强类,那么所有请求后端的接口都将先走改类的逻辑,参数进行过滤

2、自定义过滤器并注入全局bean

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 {

HttpServletRequest request = (HttpServletRequest)servletRequest;

XssHttpRequestWrapper requestWrapper = new XssHttpRequestWrapper(request);

filterChain.doFilter(requestWrapper,servletResponse);

}

@Override

public void destroy() {

}

}

@Configuration

public class XSSFilterRegister {

@Bean

public FilterRegistrationBean RegistTest1(){

//通过FilterRegistrationBean实例设置优先级可以生效

FilterRegistrationBean bean = new FilterRegistrationBean();

bean.setFilter(new XssFilter());//注册自定义过滤器

bean.setName("flilter");//过滤器名称

bean.addUrlPatterns("/*");//过滤所有路径

return bean;

}

}

仍然使用上面的接口做一下测试

@PostMapping("/getAccName")

public String getAccName(@RequestBody NameParams params){

return "name is : "+ params.getName();

}

通过这种方式,直接将注入的敏感标签符号去掉,这样确保了入库的数据的安全性,返回给页面的数据就不存在非法html标签问题了

String value = values[i];

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

values[i]=value;

}

}

return values;

}

@Override

public Map getParameterMap() {

Map parameters = super.getParameterMap();

Map map = new LinkedHashMap<>();

if(parameters !=null){

for(String key : parameters.keySet()){

String[] values = parameters.get(key);

for(int i=0;i

String value = values[i];

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

values[i]=value;

}

map.put(key,values);

}

}

return map;

}

@Override

public String getHeader(String name) {

String value = super.getHeader(name);

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

return value;

}

@Override

public ServletInputStream getInputStream() throws IOException {

InputStream in = super.getInputStream();

InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));

BufferedReader buffer = new BufferedReader(reader);

StringBuffer body = new StringBuffer();

String line = buffer.readLine();

while (line !=null){

body.append(line);

line = buffer.readLine();

}

buffer.close();

reader.close();

in.close();

Map map = JSONUtil.parseObj(body.toString());

Map result = new LinkedHashMap<>();

for(String key : map.keySet()){

Object val = map.get(key);

if(val instanceof String){

if(!StringUtils.isEmpty(val.toString())){

result.put(key,HtmlUtil.filter(val.toString()));

}

}else {

result.put(key,val);

}

}

String json = JSONUtil.toJsonStr(result);

ByteArrayInputStream bain = new ByteArrayInputStream(json.getBytes());

return new ServletInputStream() {

@Override

public boolean isFinished() {

return false;

}

@Override

public boolean isReady() {

return false;

}

@Override

public void setReadListener(ReadListener readListener) {

}

@Override

public int read() throws IOException {

return bain.read();

}

};

}

}

可以理解为,在自定义过滤器中添加上面的增强类,那么所有请求后端的接口都将先走改类的逻辑,参数进行过滤

2、自定义过滤器并注入全局bean

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 {

HttpServletRequest request = (HttpServletRequest)servletRequest;

XssHttpRequestWrapper requestWrapper = new XssHttpRequestWrapper(request);

filterChain.doFilter(requestWrapper,servletResponse);

}

@Override

public void destroy() {

}

}

@Configuration

public class XSSFilterRegister {

@Bean

public FilterRegistrationBean RegistTest1(){

//通过FilterRegistrationBean实例设置优先级可以生效

FilterRegistrationBean bean = new FilterRegistrationBean();

bean.setFilter(new XssFilter());//注册自定义过滤器

bean.setName("flilter");//过滤器名称

bean.addUrlPatterns("/*");//过滤所有路径

return bean;

}

}

仍然使用上面的接口做一下测试

@PostMapping("/getAccName")

public String getAccName(@RequestBody NameParams params){

return "name is : "+ params.getName();

}

通过这种方式,直接将注入的敏感标签符号去掉,这样确保了入库的数据的安全性,返回给页面的数据就不存在非法html标签问题了

String value = values[i];

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

values[i]=value;

}

map.put(key,values);

}

}

return map;

}

@Override

public String getHeader(String name) {

String value = super.getHeader(name);

if(!StringUtils.isEmpty(value)){

value = HtmlUtil.filter(value);

}

return value;

}

@Override

public ServletInputStream getInputStream() throws IOException {

InputStream in = super.getInputStream();

InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));

BufferedReader buffer = new BufferedReader(reader);

StringBuffer body = new StringBuffer();

String line = buffer.readLine();

while (line !=null){

body.append(line);

line = buffer.readLine();

}

buffer.close();

reader.close();

in.close();

Map map = JSONUtil.parseObj(body.toString());

Map result = new LinkedHashMap<>();

for(String key : map.keySet()){

Object val = map.get(key);

if(val instanceof String){

if(!StringUtils.isEmpty(val.toString())){

result.put(key,HtmlUtil.filter(val.toString()));

}

}else {

result.put(key,val);

}

}

String json = JSONUtil.toJsonStr(result);

ByteArrayInputStream bain = new ByteArrayInputStream(json.getBytes());

return new ServletInputStream() {

@Override

public boolean isFinished() {

return false;

}

@Override

public boolean isReady() {

return false;

}

@Override

public void setReadListener(ReadListener readListener) {

}

@Override

public int read() throws IOException {

return bain.read();

}

};

}

}

可以理解为,在自定义过滤器中添加上面的增强类,那么所有请求后端的接口都将先走改类的逻辑,参数进行过滤

2、自定义过滤器并注入全局bean

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 {

HttpServletRequest request = (HttpServletRequest)servletRequest;

XssHttpRequestWrapper requestWrapper = new XssHttpRequestWrapper(request);

filterChain.doFilter(requestWrapper,servletResponse);

}

@Override

public void destroy() {

}

}

@Configuration

public class XSSFilterRegister {

@Bean

public FilterRegistrationBean RegistTest1(){

//通过FilterRegistrationBean实例设置优先级可以生效

FilterRegistrationBean bean = new FilterRegistrationBean();

bean.setFilter(new XssFilter());//注册自定义过滤器

bean.setName("flilter");//过滤器名称

bean.addUrlPatterns("/*");//过滤所有路径

return bean;

}

}

仍然使用上面的接口做一下测试

@PostMapping("/getAccName")

public String getAccName(@RequestBody NameParams params){

return "name is : "+ params.getName();

}

通过这种方式,直接将注入的敏感标签符号去掉,这样确保了入库的数据的安全性,返回给页面的数据就不存在非法html标签问题了

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:公众号电影api(公众号电影票打折购买是真的吗)
下一篇:免费api天气(天气网api)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~