Java过滤XSS脚本攻击详细代码示例

 更新时间:2024年10月11日 11:41:45   作者:IAmZRH  
这篇文章主要介绍了Java过滤XSS脚本攻击的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

背景

之前公司信息安全部门对公司项目进行网络安全升级时,发现项目里可能会出现XSS脚本攻击漏洞,所以就需要对其参数进行过滤拦截。

XSS

百度百科:XSS攻击全称:cross site scripting(这里是为了和CSS区分,所以叫XSS),跨站脚本攻击(XSS),是最普遍的Web应用安全漏洞。这类漏洞能够使得攻击者嵌入恶意脚本代码到正常用户会访问到的页面中,当正常用户访问该页面时,则可导致嵌入的恶意脚本代码的执行,从而达到恶意攻击用户的目的。攻击者可以使用户在浏览器中执行其预定义的恶意脚本,其导致的危害可想而知,如劫持用户会话,插入恶意内容、重定向用户、使用恶意软件劫持用户浏览器、繁殖XSS蠕虫,甚至破坏网站、修改路由器配置信息等。

  • xss漏洞攻击分为三种:
    • 反射性XSS攻击:前端在发送请求时,在url参数里携带一些脚本命令,然后等服务端把脚本在反射给浏览器执行脚本代码,进行XSS漏洞攻击
    • 存储性XSS攻击:和反射性XSS漏洞攻击相似,但是服务器会进行持久化保存脚本命令,后续用户访问该数据时持久性进行XSS漏洞攻击
    • DOS性XSS攻击:和服务端没有交互,靠浏览器的DOM解析进行XSS攻击

Java过滤

  • 预防XSS漏洞攻击除了web端进行解析过滤外,也还需要服务端进行校验过滤
  • 本次使用springboot项目中过滤器进行对前端传来的参数进行过滤拦截
/**
 * springboot注册过滤器
 *
 * @author: zrh
 * @date: 2021-11-17
 */

@Configuration
public class XssFilterConfig {

    @Bean
    public FilterRegistrationBean xssFilterRegistrationBean () {
        FilterRegistrationBean initXssFilterBean = new FilterRegistrationBean();
        // 设置自定义过滤器
        initXssFilterBean.setFilter(new XssFilter());
        // 设置优先级(值越低,优先级越高)
        initXssFilterBean.setOrder(1);
        // 设置过滤路径
        initXssFilterBean.addUrlPatterns("/*");
        // 设置过滤器名称
        initXssFilterBean.setName("XSS_filter");
        // 设置过滤器作用范围(可以配置多种,这里指定过滤请求资源)
        initXssFilterBean.setDispatcherTypes(DispatcherType.REQUEST);
        return initXssFilterBean;
    }
}
  • spring项目中可以使用web.xml定义过滤器,springboot中没有web.xml配置文件,那么就可以使用FilterRegistrationBean类把过滤器实例注册到容器
/**
 * 自定义过滤器
 *
 * @author: zrh
 * @date: 2021-11-17
 */
@Slf4j
public class XssFilter implements Filter {

    @Override
    public void init (FilterConfig filterConfig) {
        // 初始化调用
    }

    @Override
    public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        final XssHttpServletRequestWrapper requestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        filterChain.doFilter(requestWrapper, servletResponse);
    }

    @Override
    public void destroy () {
        // 销毁调用
    }
}
/**
 * 重写请求参数过滤
 *
 * @author: zrh
 * @date: 2021-11-17
 */
@Slf4j
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    public XssHttpServletRequestWrapper (HttpServletRequest request) {
        super(request);
    }

    /**
     * 对GET请求中参数进行过滤校验
     *
     * @param name
     * @return
     */
    @Override
    public String[] getParameterValues (String name) {
        String[] values = super.getParameterValues(name);
        if (values == null) {
            return null;
        }
        int count = values.length;
        String[] cleanParams = new String[count];
        for (int i = 0; i < count; i++) {
            cleanParams[i] = String.valueOf(XssUtil.filterParam(values[i]));
            log.info("getParameterValues -> name:{},过滤前参数:{},过滤后参数:{}", name, values[i], cleanParams[i]);
        }
        return cleanParams;
    }

    /**
     * 对POST请求头进行参数过滤校验
     *
     * @param header
     * @return
     */
    @Override
    public Enumeration getHeaders (String header) {
        final String value = super.getHeader(header);
        final LinkedList list = new LinkedList();
        if (value != null) {
            final Object param = XssUtil.filterParam(value);
            list.addFirst(param);
            log.info("getHeaders -> header:{},过滤前参数:{},过滤后参数:{}", header, value, param);
        }
        return Collections.enumeration(list);
    }

    /**
     * 对POST请求中body参数进行校验
     *
     * @return
     * @throws IOException
     */
    @Override
    public ServletInputStream getInputStream () throws IOException {
        final ByteArrayInputStream stream = new ByteArrayInputStream(inputHandlers(super.getInputStream()).getBytes());
        return new ServletInputStream() {
            @Override
            public int read () {
                return stream.read();
            }

            @Override
            public boolean isFinished () {
                return false;
            }

            @Override
            public boolean isReady () {
                return false;
            }

            @Override
            public void setReadListener (ReadListener readListener) {
            }
        };
    }

    /**
     * 解析请求流参数
     *
     * @param servletInputStream
     * @return
     */
    public String inputHandlers (ServletInputStream servletInputStream) {
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(servletInputStream, Charset.forName("UTF-8")));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            log.error("异常 e:", e);
        } finally {
            if (servletInputStream != null) {
                try {
                    servletInputStream.close();
                } catch (IOException e) {
                    log.error("servletInputStream 关闭异常 e:", e);
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    log.error("reader 关闭异常 e:", e);
                }
            }
        }
        final String param = XssUtil.filterBody(sb.toString());
        log.info("getInputStream -> 过滤前参数:{},过滤后参数:{}", sb, param);
        return param;
    }
}
  • 重写HttpServletRequestWrapper类用于过滤改变请求参数值
/**
 * 参数校验工具类
 *
 * @author: zrh
 * @date: 2021-11-17
 */
@Slf4j
public final class XssUtil {

    private XssUtil () {
    }

    /**
     * 网上找的XSS匹配正则表达式
     */
    private final static Pattern[] PATTERNS = new Pattern[]{
            // Script fragments
            Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
            // src='...'
            Pattern.compile("src[\r\n]*=[\r\n]*\'(.*?)\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            Pattern.compile("src[\r\n]*=[\r\n]*\"(.*?)\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            // lonely script tags
            Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
            Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            // eval(...)
            Pattern.compile("eval\((.*?)\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            // expression(...)
            Pattern.compile("expression\((.*?)\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            // javascript:...
            Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
            // vbscript:...
            Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
            // 空格英文单双引号
            Pattern.compile("[\s'"]+", Pattern.CASE_INSENSITIVE),
            // onload(...)=...
            Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            // alert
            Pattern.compile("alert(.*?)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            Pattern.compile("<", Pattern.MULTILINE | Pattern.DOTALL),
            Pattern.compile(">", Pattern.MULTILINE | Pattern.DOTALL),
            //Checks any html tags i.e. <script, <embed, <object etc.
            Pattern.compile("(<(script|iframe|embed|frame|frameset|object|img|applet|body|html|style|layer|link|ilayer|meta|bgsound))")
    };

    /**
     * 对请求对象参数进行过滤校验
     *
     * @param params
     * @return
     */
    public static String filterBody (String params) {
        try {
            if (StringUtils.isBlank(params)) {
                return params;
            }
            final Map<String, Object> map = JSONObject.parseObject(params, Map.class);
            if (map.isEmpty()) {
                return params;
            }

            // 参数过滤
            final Iterator<Map.Entry<String, Object>> iterator = map.entrySet().stream().iterator();
            while (iterator.hasNext()) {
                final Map.Entry<String, Object> next = iterator.next();
                next.setValue(filterParam(next.getValue()));
            }
            return JSON.toJSONString(map);
        } catch (Exception e) {
            log.error("XSS过滤异常:", e);
        }
        return params;
    }

    /**
     * 对请求字符串参数进行过滤校验
     *
     * @param param
     * @param <T>
     * @return
     */
    public static <T> Object filterParam (T param) {
        if (param instanceof String) {
            try {
                String value = String.valueOf(param);
                for (Pattern pattern : PATTERNS) {
                    value = pattern.matcher(value).replaceAll("");
                }
                return value;
            } catch (Exception e) {
                log.error("XSS参数过滤异常:", e);
            }
        }
        return param;
    }
}
  • XSS过滤参数的正则工具类
/**
 *
 * @Author: ZRH
 * @Date: 2021/11/17
 */
@RestController
public class XssTest {

    @PostMapping("/xss/test")
    public String test (@RequestBody JSONObject jsonObject) {
        System.out.println(jsonObject.toJSONString());
        return "OK";
    }

    @GetMapping("/xss/test")
    public String test (@RequestParam Integer data, @RequestParam String result) {
        System.out.println(data);
        return "OK";
    }
}

模拟请求响应结果:
17:07:06.597 - [http-nio-8888-exec-1] - getHeaders -> header:content-type,过滤前参数:application/json,过滤后参数:application/json
17:07:06.598 - [http-nio-8888-exec-1] - getHeaders -> header:token,过滤前参数:123,过滤后参数:123
17:07:06.598 - [http-nio-8888-exec-1] - getHeaders -> header:a,过滤前参数:123,过滤后参数:123
17:07:06.598 - [http-nio-8888-exec-1] - getHeaders -> header:b,过滤前参数:<script>alert("XSS");</script>,过滤后参数:
17:07:06.599 - [http-nio-8888-exec-1] - getHeaders -> header:content-length,过滤前参数:67,过滤后参数:67
17:07:06.599 - [http-nio-8888-exec-1] - getHeaders -> header:host,过滤前参数:localhost:8888,过滤后参数:localhost:8888
17:07:06.599 - [http-nio-8888-exec-1] - getHeaders -> header:connection,过滤前参数:Keep-Alive,过滤后参数:Keep-Alive
17:07:06.599 - [http-nio-8888-exec-1] - getHeaders -> header:user-agent,过滤前参数:Apache-HttpClient/4.5.12 (Java/11.0.8),过滤后参数:Apache-HttpClient/4.5.12(Java/11.0.8)
17:07:06.599 - [http-nio-8888-exec-1] - getHeaders -> header:accept-encoding,过滤前参数:gzip,deflate,过滤后参数:gzip,deflate
17:07:06.648 - [http-nio-8888-exec-1] - getInputStream -> 过滤前参数:{  "a": "1",  "b": 2,  "c": "<script>alert(\"XSS\");</script>"},过滤后参数:{"a":"1","b":2,"c":""}
{"a":"1","b":2,"c":""}

最后

  • 除了可以使用过滤器以外,还可以使用拦截器进行拦截校验。大致流程也差不多,先获取参数,然后进行校验,最后重新赋值。
  • 上述代码例子只是简单粗化版,在实际项目中要根据需求进行代码调整和性能优化后才可在线上使用。

到此这篇关于Java过滤XSS脚本攻击的文章就介绍到这了,更多相关Java过滤XSS脚本攻击内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现按行读取大文件

    Java实现按行读取大文件

    这篇文章主要介绍了Java实现按行读取大文件的方法的小结,非常的简单实用,有需要的小伙伴尅参考下。
    2015-05-05
  • 浅析SpringCloud Alibaba-Nacos 作为注册中心示例代码

    浅析SpringCloud Alibaba-Nacos 作为注册中心示例代码

    这篇文章主要介绍了SpringCloud Alibaba-Nacos 作为注册中心示例代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • java 正则,object中两个方法的使用(详解)

    java 正则,object中两个方法的使用(详解)

    下面小编就为大家带来一篇java 正则,object中两个方法的使用(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • idea maven pom不自动更新的解决方法

    idea maven pom不自动更新的解决方法

    这篇文章主要介绍了idea maven pom不自动更新的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Ubuntu 安装 JDK8 的两种方法(总结)

    Ubuntu 安装 JDK8 的两种方法(总结)

    下面小编就为大家带来一篇Ubuntu 安装 JDK8 的两种方法(总结)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • JAVA GUI自定义JPanel画板背景

    JAVA GUI自定义JPanel画板背景

    这篇文章主要为大家详细介绍了JAVA GUI自定义JPanel画板背景的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • 详解Java如何在Array和List之间进行转换

    详解Java如何在Array和List之间进行转换

    这篇文章主要为大家介绍了详解Java如何在Array和List之间进行转换的方法示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 带你深入理解MyBatis缓存机制

    带你深入理解MyBatis缓存机制

    缓存是一般的ORM框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力,跟Hibernate 一样,MyBatis 也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口,这篇文章主要给大家介绍了关于MyBatis缓存机制的相关资料,需要的朋友可以参考下
    2021-10-10
  • Java springboot接口迅速上手,带你半小时极速入门

    Java springboot接口迅速上手,带你半小时极速入门

    这篇文章主要给大家介绍了关于SpringBoot实现API接口的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-09-09
  • SpringBoot spring.factories加载时机分析

    SpringBoot spring.factories加载时机分析

    这篇文章主要为大家介绍了SpringBoot spring.factories加载时机分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论