实战项目如何抵御即跨站脚本(XSS)攻击

news2024/12/23 15:44:31

一、XSS攻击的危害

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

例如用户在发帖或者注册的时候,在文本框中输入<script>alert('xss')</script>,这段代码如果不经过转义处理,而直接保存到数据库。将来视图层渲染HTML的时候,把这段代码输出到页面上,那么<script>标签的内容就会被执行。

通常情况下,我们登陆到某个网站。如果网站使用HttpSession保存登陆凭证,那么SessionId会以Cookie的形式保存在浏览器上。如果黑客在这个网页发帖的时候,填写的Javascript代码是用来获取Cookie内容的,并且把Cookie内容通过Ajax发送给黑客自己的电脑。于是只要有人在这个网站上浏览黑客发的帖子,那么视图层渲染HTML页面,就会执行注入的XSS脚本,于是你的Cookie信息就泄露了。黑客在自己的电脑上构建出Cookie,就可以冒充已经登陆的用户。

即便很多网站使用了JWT,登陆凭证(Token令牌)是存储在浏览器上面的。所以用XSS脚本可以轻松的从Storage中提取出Token,黑客依然可以轻松的冒充已经登陆的用户。

所以避免XSS攻击最有效的办法就是对用户输入的数据进行转义,然后存储到数据库里面。等到视图层渲染HTML页面的时候。转义后的文字是不会被当做JavaScript执行的,这就可以抵御XSS攻击。

二、解决思路

对Http请求中的数据转义,即可以设置过滤器,来覆盖Http请求的方法,可参考如下两个方法:

实现HttpServletRequest接口,各家服务器厂商会实现它。但问题是如果直接继承各厂商的请求父类,那么我们的程序就跟厂商绑定在一起

继承HttpServletRequestWrapper类。HttpServletRequestWrapper类使用了装饰器模式;装饰器封装了厂商的Request;只需实现类只需要覆盖Wrapper类的方法,就能做

最后创建过滤器,把Requestx对象传入Wrapper>对象

三、代码实现

1、导入Hutool依赖库

因为Hutool工具包带有XSS转义的工具类,所以我们要导入Hutool,然后利用Servlet规范提供的请求包装类,定义数据转义功能。

  <dependency>
       <groupId>cn.hutool</groupId>
       <artifactId>hutool-all</artifactId>
       <version>5.8.0</version>
   </dependency>

2、定义请求包装类

我们平时写Web项目遇到的HttpServletRequest,它其实是个接口。如果我们想要重新定义请求类,扩展这个接口是最不应该的。因为HttpServletRequest接口中抽象方法太多了,我们逐一实现起来太耗费时间。所以我们应该挑选一个简单一点的自定义请求类的方式。那就是继承HttpServletRequestWrapper父类。

JavaEE只是一个标准,具体的实现由各家应用服务器厂商来完成。比如说Tomcat在实现Servlet规范的时候,就自定义了HttpServletRequest接口的实现类。同时JavaEE规范还定义了HttpServletRequestWrapper,这个类是请求类的包装类,用上了装饰器模式。这里用到的设计模式装饰器模式,无论各家应用服务器厂商怎么去实现HttpServletRequest接口,用户想要自定义请求,只需要继承HttpServletRequestwrapper,对应覆盖某个方法即可,然后把请求传入请求包装类,装饰器模式就会替代请求对象中对应的某个方法。用户的代码和服务器厂商的代码完全解耦,我们不用关心HttpServletRequest接口是怎么实现的,借助于包装类我们可以随意修改请求中的方法。

XssHttpServletRequestWrapper

/**
 * @description: 抵御跨站脚本XSS攻击
 * @Title: XssHttpServletRequestWrapper
 * @Package com.vector.server.config.xss
 * @Author 芝士汉堡
 * @Date 2022/12/4 7:54
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {


    /*getInputStream方法
     *  springMVC是通过这个方法,从请求里面提取客户端提交的数据,
     *  然后把这些数据封装到from对象里面,然后把这个from对象传递给控制器方法,
     *  如果不对getInputStream方法读取的数据进行转译,后端就不具备防御XSS攻击的能力。
     *
     * */

    /**
     * The default behavior of this method is to return getInputStream() on the
     * wrapped request object.
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
        InputStream inputStream = super.getInputStream();
        InputStreamReader reader = new InputStreamReader(inputStream, 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();
        inputStream.close();
        /*将读取的body进行数据转换,因为客户端提交是json格式的,
        java是不支持原生json格式,需将json格式数据转为map对象*/
        Map<String, Object> map = JSONUtil.parseObj(body.toString());
        /*对map进行转译*/
        Map<String, Object> result = new LinkedHashMap<>();
        for (String key : map.keySet()) {
            Object val = map.get(key);
            if (val instanceof String) {
                if (!StrUtil.hasEmpty(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 int read() throws IOException {
                return bain.read();
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }

    /**
     * Constructs a request object wrapping the given request.
     *
     * @param request The request to wrap
     * @throws IllegalArgumentException if the request is null
     */
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    /**
     * The default behavior of this method is to return getParameter(String
     * name) on the wrapped request object.
     * 重写getParameter方法,将参数名和参数值都做xss过滤。
     *
     * @param name
     */
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (!StrUtil.hasEmpty(value)) {
            value = HtmlUtil.filter(value);
        }
        return value;
    }


    /**
     * The default behavior of this method is to return
     * getParameterValues(String name) on the wrapped request object.
     * 做转译处理
     *
     * @param name
     */
    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                String value = values[i];
                if (!StrUtil.hasEmpty(value)) {
                    value = HtmlUtil.filter(value);
                }
                values[i] = value;
            }
        }
        return values;
    }

    /**
     * The default behavior of this method is to return getParameterMap() on the
     * wrapped request object.
     */
    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> parameters = super.getParameterMap();
        LinkedHashMap<String, String[]> map = new LinkedHashMap();
        if (parameters != null) {
            for (String key : parameters.keySet()) {
                String[] values = parameters.get(key);
                for (int i = 0; i < values.length; i++) {
                    String value = values[i];
                    if (!StrUtil.hasEmpty(value)) {
                        value = HtmlUtil.filter(value);
                    }
                    values[i] = value;
                }
                map.put(key, values);
            }
        }
        return map;
    }

    /**
     * The default behavior of this method is to return getHeader(String name)
     * on the wrapped request object.
     *
     * @param name
     */
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (!StrUtil.hasEmpty(value)) {
            value = HtmlUtil.filter(value);
        }
        return value;
    }
}

3、创建过滤器,把Requestx对象传入Wrapper>对象


/**
 * @description: 将拦截下的请求封装为XssHttpServletRequestWrapper对象
 * @Title: XssFilter
 * @Package com.vector.server.config.xss
 * @Author 芝士汉堡
 * @Date 2022/12/4 8:47
 */
@WebFilter(filterName = "xssFilter", urlPatterns = "/*")
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 {
        chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
    }

    @Override
    public void destroy() {
    }

}


四、测试

向后端发送数据

{
  "name": "<script>alert(1234)</script>"
}

接口逻辑

@RestController
@RequestMapping("/test")
@Api("测试Web接口")
public class TestController {

    @PostMapping("/sayHello")
    @ApiOperation("最简单的测试方法")
    public R sayHello(@Valid @RequestBody TestSayHelloForm form){
        return R.ok().put("message", "Hello"+form.getName());
    }
}

测试结果
在这里插入图片描述
将JavaScript代码屏蔽。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59408.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

思派健康通过上市聆讯:F轮估值17亿美元 腾讯是大股东

雷递网 雷建平 12月3日思派健康科技日前通过聆讯&#xff0c;准备在香港上市。思派健康早在2021年8月就已经递交招股书&#xff0c;这是时隔一年多后&#xff0c;这之前第三次递交招股书。这也意味着&#xff0c;时隔一年多后&#xff0c;思派健康终于要上市了。上半年亏损3.5亿…

SpringSecurity(八)【会话管理】

八、会话管理 简介 当浏览器调用登录接口登录成功之后&#xff0c;服务端会和浏览器之间创建一个会话&#xff08;Session&#xff09;&#xff0c;浏览器在每次发送请求时都会携带一个 SessionId&#xff0c;服务端则根据这个 SessionId 来判断用户身份。当浏览器关闭之后&…

从硬件角度看服务器性能调优

bios整体配置bios系统设置Hyper Thread开启超线程&#xff0c;设置后lscpu命令Thread(s) per core 值显示为 2。超线程可以理解为CPU的虚拟化&#xff0c;一颗物理CPU并行执行两条流水线指令。确认处理器基本频率及睿频频率&#xff0c;部分处理器基础频率低&#xff0c;但是睿…

看完了你还能不懂JAVA内存模型(JMM),我输了

前言 开篇一个例子&#xff0c;我看看都有谁会&#xff1f;如果不会的&#xff0c;或者不知道原理的&#xff0c;还是老老实实看完这篇文章吧。 Slf4j(topic "c.VolatileTest") public class VolatileTest { static boolean run true; public static void main(S…

基于Java+Swing实现《扫雷》游戏

基于JavaSwing实现《扫雷》游戏一、系统介绍二、功能展示三、其他系统一、系统介绍 windows自带的游戏《扫雷》是陪伴了无数人的经典游戏&#xff0c;本程序参考《扫雷》的规则进行了简化&#xff0c;用java语言实现&#xff0c;采用了swing技术进行了界面化处理&#xff0c;设…

基于蚁群算法求解运钞车路径规划问题(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

[附源码]JAVA毕业设计桔子酒店客房管理系统(系统+LW)

[附源码]JAVA毕业设计桔子酒店客房管理系统&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目…

vue app开发调用原生方法实现权限访问授权处理(一)

vue app开发调用原生方法实现权限访问授权处理 前提&#xff1a;在写代码之前应该想清楚调用原生安卓、ios的方法&#xff0c;就应该遵循双端的方法规则&#xff0c;调用方法时应该注意&#xff0c;在这里先主要介绍一下注意事项&#xff1a; 根据App发布应用市场的要求&…

【sciter】安全应用列表控件总结

一、效果图 二、功能点 实现电脑文件拖拽进入到安全桌面,读取文件路径,生成应用。可以配置允许拖拽进入安全桌面的文件应用。点击添加图标,可以添加应用到安全桌面中。在安全桌面列表中每一个应用实现双击、失去焦点,获取焦点、右键事件在安全桌面列表中每一个应用可以实现…

[附源码]计算机毕业设计springboot疫情防控平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

HTML5期末大作业:用DIV+CSS技术设计的网页与实现(剪纸传统文化网页设计主题)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

二本土木工程管理毕业5年,零基础转型大数据开发,收割长沙深圳多个大数据offer...

点击上方 "大数据肌肉猿"关注, 星标一起成长点击下方链接&#xff0c;进入高质量学习交流群今日更新| 1052个转型案例分享-大数据交流群分享一位学习群同学的转型经历&#xff0c;他是二本土木类工程管理专业&#xff0c;17年毕业&#xff0c;毕业后在长沙工地从事了…

Java基于springboot+vue的汽车饰品销售购物商城系统 前后端分离

开发背景 随着我国科技和经济的发展&#xff0c;我国的汽车数量也越来越多&#xff0c;基本家家户户都拥有了自己的汽车&#xff0c;为了让汽车用起来更加的舒心&#xff0c;于是各类琳琅满目的汽车饰品也出现了。大多数时候人们在购买汽车饰品的时候都回到这些专卖店购买&…

C++之面向对象

目录 对象与类 类的语法&#xff1a; C中class与struct的区别&#xff1a; 通过类实例化对象的方式 具体案例 类作用域与分文件编写 创建circle.h头文件 创建源文件circle.cpp 创建all.cpp来作为程序的入口 封装 封装的意义 访问权限符 成员属性私有化 优点 具体…

Python解题 - 括号上色(递归)

题目 小艺酱又得到了一堆括号。括号是严格匹配的。现在给括号进行上色。上色有三个要求&#xff1a; 1、只有三种上色方案&#xff0c;不上色&#xff0c;上红色&#xff0c;上蓝色。 2、每对括号只有一个上色。 3、相邻的两个括号不能上相同的颜色&#xff0c;但是可以都不上色…

【Java面试指北】Exception Error Throwable 你分得清么?

读本篇文章之前&#xff0c;如果让你叙述一下 Exception Error Throwable 的区别&#xff0c;你能回答出来么&#xff1f; 你的反应是不是像下面一样呢&#xff1f; 你在写代码时会经常 try catch(Exception)在 log 中会看到 OutOfMemoryErrorThrowable 似乎不常见&#xff0c…

为什么大部分人做网赚是赚不到钱的,这才是真正的原因!

说实话&#xff0c;互联网已经发展到现在的水平&#xff0c;目前来看&#xff0c;互联网上只存在两种平台&#xff0c;一种是社交平台&#xff0c;一种是内容平台。 所有的抖音、知乎、小红书、搜索引擎、淘宝等等这些都是内容平台&#xff0c;如果你想要解决精准流量问题&…

JSP+MySQL基于SSM的高校毕业生就业管理系统

本高校毕业生就业管理系统主要包括系统用户管理模块、招聘信息管理模块、简历接收管理、投递简历管理、登录模块、和退出模块等多个模块。它帮助高校毕业生就业管理实现了信息化、网络化,通过测试,实现了系统设计目标,相比传统的管理模式,本系统合理的利用了高校毕业生就业管理…

配电网重构|基于新颖的启发式算法SOE的随机(SDNR)配电网重构(Matlab代码实现)【算例33节点、84节点、119节点、136节点、417节点】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f4dd;目前更新&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;电力系统相关知识&#xff0c;期刊论文&…

【数据集NO.3】人脸识别数据集汇总

文章目录前言一、IMDB-WIKI人脸数据集二、WiderFace人脸检测数据集三、GENKI 人脸图像数据集四、哥伦比亚大学公众人物脸部数据库五、CelebA人脸数据集六、美国国防部人脸库七、MTFL人脸识别数据集八、BioID人脸数据集九、PersonID人脸识别数据集十、CMU PIE人脸库十一、Youtub…