一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringBoot2.x 整合 AntiSamy防御XSS攻擊的簡單總結

SpringBoot2.x 整合 AntiSamy防御XSS攻擊的簡單總結

2021-12-06 13:25RtxTitanV Java教程

本文主要對SpringBoot2.x集成AntiSamy防御XSS攻擊進行簡單總結,其中SpringBoot使用的2.4.5版本,通過示例代碼給大家介紹的非常詳細,需要的朋友參考下吧

AntiSamy是OWASP的一個開源項目,通過對用戶輸入的HTML、CSS、JavaScript等內容進行檢驗和清理,確保輸入符合應用規范。AntiSamy被廣泛應用于Web服務對存儲型和反射型XSS的防御中。

XSS攻擊全稱為跨站腳本攻擊(Cross Site Scripting),是一種在web應用中的計算機安全漏洞,它允許用戶將惡意代碼(如script腳本)植入到Web頁面中,為了不和層疊樣式表(Cascading Style Sheets, CSS)混淆,一般縮寫為XSS。XSS分為以下兩種類型:

  • 存儲型XSS:服務端對用戶輸入的惡意腳本沒有經過驗證就存入數據庫,每次調用數據庫都會將其渲染在瀏覽器上。則可能為存儲型XSS。
  • 反射型XSS:通過get或者post等方式,向服務端輸入數據。如果服務端不進行過濾,驗證或編碼,直接將用戶信息呈現出來,可能會造成反射型XSS。

本文主要對SpringBoot2.x集成AntiSamy防御XSS攻擊進行簡單總結,其中SpringBoot使用的2.4.5版本。

一、引入依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- AntiSamy依賴 -->
<dependency>
    <groupId>org.owasp.antisamy</groupId>
    <artifactId>antisamy</artifactId>
    <version>1.6.2</version>
</dependency>
<!-- lombok插件 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.9</version>
</dependency>

二、策略文件

Antisamy對惡意代碼的過濾依賴于策略文件,策略文件為xml格式,規定了AntiSamy對各個標簽、屬性的處理方法。策略文件定義的嚴格與否,決定了AntiSamy對Xss的防御效果。在AntiSamy的jar包中,已經包含了幾個常用的策略文件:

SpringBoot2.x 整合 AntiSamy防御XSS攻擊的簡單總結

本文使用antisamy-ebay.xml作為策略文件,該策略相對安全,適用于電商網站。將antisamy-ebay.xmlantisamy.xsd復制到resouces目錄下。對于策略文件的具體內容這里不進行深入了解,只需了解下對標簽的處理規則<tag-rules>,共有remove、truncate、validate三種處理方式,其中remove為直接刪除,truncate為縮短標簽,只保留標簽和值,validate為驗證標簽屬性:

SpringBoot2.x 整合 AntiSamy防御XSS攻擊的簡單總結

上圖截取了<tag-rules>的一部分,可知對script標簽的處理策略是remove。

三、實體類和Controller

用戶實體類:

package com.rtxtitanv.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.model.User
 * @description 用戶實體類
 * @date 2021/8/23 14:54
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    private Long id;
    private String username;
    private String password;
}

Controller:

package com.rtxtitanv.controller;

import com.rtxtitanv.model.User;
import org.springframework.web.bind.annotation.*;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.controller.UserController
 * @description UserController
 * @date 2021/8/23 14:54
 */
@RequestMapping("/user")
@RestController
public class UserController {

    @PostMapping("/save")
    public User saveUser(User user) {
        return user;
    }

    @GetMapping("/get")
    public User getUserById(@RequestParam(value = "id") Long id) {
        return new User(id, "ZhaoYun", "123456");
    }

    @PutMapping("/update")
    public User updateUser(@RequestBody User user) {
        return user;
    }
}

四、創建過濾器

package com.rtxtitanv.filter;

import com.rtxtitanv.wrapper.XssRequestWrapper;

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

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.filter.XssFilter
 * @description XSS過濾器
 * @date 2021/8/23 15:01
 */
public class XssFilter implements Filter {

    private FilterConfig filterConfig;

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

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        // 攔截請求,處理XSS過濾
        chain.doFilter(new XssRequestWrapper((HttpServletRequest)request), response);
    }

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

注意:在過濾器中并沒有直接對請求參數進行過濾清洗,而是在XssRequestWrapper類中進行的。XssRequestWrapper類將當前的request對象進行了包裝,在過濾器放行時會自動調用XssRequestWrapper中的方法對請求參數進行清洗。

五、創建XssRequestWrapper類

package com.rtxtitanv.wrapper;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.owasp.validator.html.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Map;
import java.util.Objects;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.wrapper.XssRequestWrapper
 * @description 裝飾器模式加強對request的處理,基于AntiSamy進行XSS防御
 * @date 2021/8/23 15:01
 */
public class XssRequestWrapper extends HttpServletRequestWrapper {

    private static final Logger LOGGER = LoggerFactory.getLogger(XssRequestWrapper.class);
    private static Policy policy = null;

    static {
        try {
            // 獲取策略文件路徑,策略文件需要放到項目的classpath下
            String antiSamyPath = Objects
                .requireNonNull(XssRequestWrapper.class.getClassLoader().getResource("antisamy-ebay.xml")).getFile();
            LOGGER.info(antiSamyPath);
            // 獲取的文件路徑中有空格時,空格會被替換為%20,在new一個File對象時會出現找不到路徑的錯誤
            // 對路徑進行解碼以解決該問題
            antiSamyPath = URLDecoder.decode(antiSamyPath, "utf-8");
            LOGGER.info(antiSamyPath);
            // 指定策略文件
            policy = Policy.getInstance(antiSamyPath);
        } catch (UnsupportedEncodingException | PolicyException e) {
            e.printStackTrace();
        }
    }

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

    /**
     * 過濾請求頭
     *
     * @param name 參數名
     * @return 參數值
     */
    @Override
    public String getHeader(String name) {
        String header = super.getHeader(name);
        // 如果Header為空,則直接返回,否則進行清洗
        return StringUtils.isBlank(header) ? header : xssClean(header);
    }

    /**
     * 過濾請求參數
     *
     * @param name 參數名
     * @return 參數值
     */
    @Override
    public String getParameter(String name) {
        String parameter = super.getParameter(name);
        // 如果Parameter為空,則直接返回,否則進行清洗
        return StringUtils.isBlank(parameter) ? parameter : xssClean(parameter);
    }

    /**
     * 過濾請求參數(一個參數可以有多個值)
     *
     * @param name 參數名
     * @return 參數值數組
     */
    @Override
    public String[] getParameterValues(String name) {
        String[] parameterValues = super.getParameterValues(name);
        if (parameterValues != null) {
            int length = parameterValues.length;
            String[] newParameterValues = new String[length];
            for (int i = 0; i < length; i++) {
                LOGGER.info("AntiSamy清理之前的參數值:" + parameterValues[i]);
                // 清洗參數
                newParameterValues[i] = xssClean(parameterValues[i]);
                LOGGER.info("AntiSamy清理之后的參數值:" + newParameterValues[i]);
            }
            return newParameterValues;
        }
        return super.getParameterValues(name);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> requestMap = super.getParameterMap();
        requestMap.forEach((key, value) -> {
            for (int i = 0; i < value.length; i++) {
                LOGGER.info(value[i]);
                value[i] = xssClean(value[i]);
                LOGGER.info(value[i]);
            }
        });
        return requestMap;
    }

    /**
     * 使用AntiSamy清洗數據
     *
     * @param value 需要清洗的數據
     * @return 清洗后的數據
     */
    private String xssClean(String value) {
        try {
            AntiSamy antiSamy = new AntiSamy();
            // 使用AntiSamy清洗數據
            final CleanResults cleanResults = antiSamy.scan(value, policy);
            // 獲得安全的HTML輸出
            value = cleanResults.getCleanHTML();
            // 對轉義的HTML特殊字符(<、>、"等)進行反轉義,因為AntiSamy調用scan方法時會將特殊字符轉義
            return StringEscapeUtils.unescapeHtml4(value);
        } catch (ScanException | PolicyException e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 通過修改Json序列化的方式來完成Json格式的XSS過濾
     */
    public static class XssStringJsonSerializer extends JsonSerializer<String> {

        @Override
        public Class<String> handledType() {
            return String.class;
        }

        @Override
        public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            if (!StringUtils.isBlank(value)) {
                try {
                    AntiSamy antiSamy = new AntiSamy();
                    final CleanResults cleanResults = antiSamy.scan(value, XssRequestWrapper.policy);
                    gen.writeString(StringEscapeUtils.unescapeHtml4(cleanResults.getCleanHTML()));
                } catch (ScanException | PolicyException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

六、創建配置類

package com.rtxtitanv.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.rtxtitanv.filter.XssFilter;
import com.rtxtitanv.wrapper.XssRequestWrapper;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import javax.servlet.Filter;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.config.AntiSamyConfig
 * @description AntiSamy配置類
 * @date 2021/8/23 15:05
 */
@Configuration
public class AntiSamyConfig {

    /**
     * 配置XSS過濾器
     *
     * @return FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean<Filter> filterRegistrationBean() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(new XssFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }

    /**
     * 用于過濾Json類型數據的解析器
     *
     * @param builder Jackson2ObjectMapperBuilder
     * @return ObjectMapper
     */
    @Bean
    public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
        // 創建解析器
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        // 注冊解析器
        SimpleModule simpleModule = new SimpleModule("XssStringJsonSerializer");
        simpleModule.addSerializer(new XssRequestWrapper.XssStringJsonSerializer());
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

七、測試

啟動項目,發送如下POST請求,請求地址為http://localhost:8080/user/save,可見表單參數中的<script>標簽內容被成功過濾:

SpringBoot2.x 整合 AntiSamy防御XSS攻擊的簡單總結

發送如下GET請求,請求地址為http://localhost:8080/user/get?id=1<script>alert("XSS");</script>0,可見Query參數中的<script>標簽內容被成功過濾:

SpringBoot2.x 整合 AntiSamy防御XSS攻擊的簡單總結

發送如下PUT請求,請求地址為http://localhost:8080/user/update,可見Json類型參數中的<script>標簽內容被成功過濾:

SpringBoot2.x 整合 AntiSamy防御XSS攻擊的簡單總結

代碼示例

Github:https://github.com/RtxTitanV/springboot-learning/tree/master/springboot2.x-learning/springboot-antisamy

Gitee:https://gitee.com/RtxTitanV/springboot-learning/tree/master/springboot2.x-learning/springboot-antisamy

到此這篇關于SpringBoot2.x 整合 AntiSamy防御XSS攻擊的簡單總結的文章就介紹到這了,更多相關SpringBoot2.x防御XSS攻擊內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/RtxTitanV/article/details/119915255

延伸 · 閱讀

精彩推薦
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
主站蜘蛛池模板: 99精品视频一区在线观看miya | 国产高清好大好夹受不了了 | 亚洲视频日韩 | 亚洲欧美日韩综合一区久久 | 欧洲vodafonewifi日本 | 国产成人精品一区二三区2022 | 摄像头东北对白清晰 | 免费一级毛片在线播放放视频 | 手机看片福利盒子久久 | 成人嗯啊视频在线观看 | 久久精品熟女亚洲AV国产 | 国产欧美视频一区二区三区 | 无人知晓小说姜璟免费阅读 | 亚洲国产成人超福利久久精品 | 蜜臀91 | 男男同志videos| 免费一级国产生活片 | 17岁俄罗斯csgo | 91香蕉国产在线观看人员 | 波多野结衣在线免费观看 | 91精品国产综合久久精品 | 亚洲精品视频久久 | 欧美国产日产精品免费视频 | 欧美亚洲国产另类在线观看 | 四虎影视网址 | pppd在线播放 | 久久精品国产色蜜蜜麻豆国语版 | 日韩欧美一区二区三区免费看 | 日韩夫妻性生活 | 亚洲免费色图 | 午夜国产在线 | 好涨好爽好大视频免费 | 亚洲精品色婷婷在线影院麻豆 | 午夜影院免费体验 | 成人影院观看 | 日韩国产欧美精品综合二区 | 天天天天天天天操 | 精品久久免费视频 | 日本视频在线播放 | 男男同志videos | 晓雪老师我要进你里面好爽 |