SpringBoot中防止跨站脚本(XSS)注入攻击

一、啥为跨网站脚本呢?

1、介绍

跨网站脚本(Cross-site scripting,通常简称为XSS或跨站脚本或跨站脚本攻击)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。

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

那为啥是XSS缩写,而不是CSS呢?
Cross-site scripting的缩写是CSS,但因为CSS在网页设计领域已经被广泛指层叠样式表(Cascading Style Sheets),所以将Cross改以发音相近的X做为缩写。但早期的文件还是会使用CSS表示Cross-site scripting。

2、检测办法

通常有一些方式可以测试网站是否有正确处理特殊字符:

><script>alert(document.cookie)</script>
='><script>alert(document.cookie)</script>
"><script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert(vulnerable)</script>
%3Cscript%3Ealert('XSS')%3C/script%3E
<script>alert('XSS')</script>
<img src="javascript:alert('XSS')">
<img src="http://xxx.com/yyy.png" οnerrοr="alert('XSS')">
<div style="height:expression(alert('XSS'),1)" />(这个仅限 IE 有效)

3、攻击手段和目的

攻击者使被攻击者在浏览器中执行脚本后,如果需要收集来自被攻击者的数据(如cookie或其他敏感信息),可以自行架设一个网站,让被攻击者通过JavaScript等方式把收集好的数据作为参数提交,随后以数据库等形式记录在攻击者自己的服务器上。

4、常用的XSS攻击手段和目的

1)、盗用cookie,获取敏感信息。
2)、利用植入Flash,通过crossdomain权限设置进一步获取更高权限;或者利用Java等得到类似的操作。
3)、利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。
4)、利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。
5)、在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDoS攻击的效果。

5、漏洞的防御和利用

过滤特殊字符
避免XSS的方法之一主要是将用户所提供的内容进行过滤,许多语言都有提供对HTML的过滤:

PHP的htmlentities()或是htmlspecialchars()。
Python的cgi.escape()。
ASP的Server.HTMLEncode()。
ASP.NET的Server.HtmlEncode()或功能更强的Microsoft Anti-Cross Site Scripting Library
Java的xssprotect(Open Source Library)。
Node.js的node-validator。

二、如何造SpringBoot项目中实现防止跨站脚本(XSS)注入攻击呢?

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

1、导入Hutool工具包的依赖

<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.2</version>
</dependency>

2、添加一个Filter过滤器

package com.zjhang.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @Author: zjhang
 * @Date: 2021/6/19 14:37
 * @Description: 拦截防止注入漏洞(即防止XSS的跨站脚本攻击)
 */
@WebFilter(urlPatterns = "/*", filterName = "xssFilter")
public class XssFilter implements Filter {
    private FilterConfig filterConfig = null;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

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

    @Override
    public void destroy() {
        this.filterConfig = null;
    }
}

3、使用HttpServletRequestWrapper重新request参数

package com.zjhang.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.json.JSONUtil;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author: zjhang
 * @Date: 2021/6/19 14:37
 * @Description: 使用HttpServletRequestWrapper重新request参数
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

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

    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (!StrUtil.hasEmpty(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 < values.length; i++) {
                String value = values[i];
                if (!StrUtil.hasEmpty(value)) {
                    value = HtmlUtil.filter(value);
                }
                values[i] = value;
            }
        }
        return values;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> parameters = super.getParameterMap();
        Map<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;
    }

    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (!StrUtil.hasEmpty(value)) {
            value = HtmlUtil.filter(value);
        }
        return value;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        InputStream in = super.getInputStream();
        StringBuffer body = new StringBuffer();
        InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
        BufferedReader buffer = new BufferedReader(reader);
        String line = buffer.readLine();
        while (line != null) {
            body.append(line);
            line = buffer.readLine();
        }
        buffer.close();
        reader.close();
        in.close();

        Map<String, Object> map = JSONUtil.parseObj(body.toString());
        Map<String, Object> resultMap = new HashMap(map.size());
        for (String key : map.keySet()) {
            Object val = map.get(key);
            if (map.get(key) instanceof String) {
                resultMap.put(key, HtmlUtil.filter(val.toString()));
            } else {
                resultMap.put(key, val);
            }
        }
        String str = JSONUtil.toJsonStr(resultMap);
        final ByteArrayInputStream bain = new ByteArrayInputStream(str.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 listener) {
            }
        };
    }

}

4、给主类(启动类)添加注解

package com.zjhang;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

/**
 * @Author: zjhang
 * @Date: 2021/6/19 14:37
 * @Description: 主启动类
 */
@SpringBootApplication
@ServletComponentScan
public class ZjHangApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZjHangApplication.class, args);
    }

}

5、测试

自行测试即可!!!!!

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot本身并不提供专门的跨站脚本攻击(Cross-Site Scripting,XSS)防护功能但它提供了一些安全性相关的功能和配置选项,可以帮助我们减少XSS攻击的风险。 以下是一些常用的方法来防止Spring Boot应用程序跨站脚本攻击: 1. 输入验证和数据清洁:确保用户输入的数据进行适当的验证,过滤或转义,以防止恶意脚本注入。您可以使用一些开源库,如OWASP Java Encoder或ESAPI来进行数据清洁操作。 2. 安全头部设置:在应用程序配置安全头部,特别是设置Content Security Policy(CSP)头部。CSP可以限制哪些内容可以加载到您的应用程序防止执行恶意脚本。 3. 使用模板引擎:如果您使用模板引擎来生成HTML页面,确保正确地使用模板引擎提供的输出转义功能。这将确保任何用户输入都被正确地转义,从而防止XSS攻击。 4. 防御型编码:使用合适的方法处理用户输入,例如使用HTML转义字符(如<、>、"等)代替原始字符。这样可以确保用户输入不会被浏览器解析为恶意脚本。 5. 安全框架:Spring Security是一个强大的安全框架,可以帮助保护应用程序免受各种攻击,包括XSS。您可以使用Spring Security来配置和实施细粒度的访问控制和安全策略。 请注意,以上措施只是一些常见的防御措施,具体的安全实施需要根据您的应用程序需求和架构进行调整和定制。还请注意,安全是一个持续的过程,您应该保持关注最新的安全漏洞和最佳实践,及时更新和改进应用程序的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值