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递归运行的机制:递归的微观解读,结合图文形式详细分析了java递归运行的原理、机制与相关注意事项,需要的朋友可以参考下
    2020-03-03
  • MyBatis Plus 入门使用详细教程

    MyBatis Plus 入门使用详细教程

    这篇文章主要介绍了MyBatis Plus 入门使用详细教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • SpringBoot 集成 Memcached的方法示例

    SpringBoot 集成 Memcached的方法示例

    这篇文章主要介绍了SpringBoot 集成 Memcached的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • IDEA中的打包Build Artifacts图文详解

    IDEA中的打包Build Artifacts图文详解

    当项目开发完毕,需要对外发布时,我们就会用到IDEABuild Artifacts功能,那么如果在idea中打包呢,这篇文章主要介绍了IDEA中的打包Build Artifacts详解,需要的朋友可以参考下
    2024-03-03
  • Java阻塞队列四组API介绍(小结)

    Java阻塞队列四组API介绍(小结)

    这篇文章主要介绍了Java阻塞队列四组API介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • 如何实现Java中一个简单的LinkedList

    如何实现Java中一个简单的LinkedList

    LinkedList与ArrayList都是List接口的具体实现类。下面将介绍如何实现一个简单的LinkedList,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • 基于IDEA 的远程调试 Weblogic的操作过程

    基于IDEA 的远程调试 Weblogic的操作过程

    这篇文章主要介绍了基于IDEA 的远程调试 Weblogic的操作过程,本文通过图文实例相结合给大家介绍的非常详细,需要的朋友可以参考下
    2021-09-09
  • java去除中文括号小括号,或者英文括号的实例代码

    java去除中文括号小括号,或者英文括号的实例代码

    这篇文章主要介绍了java去除中文括号小括号,或者英文括号的实例代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • Spring Boot实战之模板引擎

    Spring Boot实战之模板引擎

    这篇文章主要介绍了Spring Boot实战之模板引擎,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • SpringBoot集成EasyExcel的步骤

    SpringBoot集成EasyExcel的步骤

    EasyExcel是阿里巴巴开源poi插件之一,主要解决了poi框架使用复杂,sax解析模式不容易操作,数据量大起来容易OOM,解决了POI并发造成的报错。主要解决方式:通过解压文件的方式加载,一行一行的加载,并且抛弃样式字体等不重要的数据,降低内存的占用。
    2021-06-06

最新评论