Spring中防止跨站指令碼 (XSS)攻擊

banq發表於2024-03-27

跨站點指令碼攻擊是一種流行且廣泛的攻擊,攻擊者將指令碼注入到 Web 應用程式中。Web 應用程式通常使用相同的來源策略,這可以防止頁面上的指令碼在來源不匹配的情況下訪問來自不同來源的資料。

因為 Spring Boot 非常重視安全性,並且由於其安全模組設定了安全標準,所以它非常強大且靈活,因此開發人員可以使用相同的來源策略來訪問不同來源的資料。儘可能至少你可以擔心安全問題。

Spring 應用程式中防止跨站指令碼 (XSS) 的示例

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class MyController {

    @RequestMapping(<font>"/form")
    public String showForm() {
        return
"form";
    }

    @PostMapping(
"/submit")
    public String submitForm(@RequestParam String userInput, Model model) {
       
// 驗證並清除使用者輸入<i>
        String sanitizedInput = validateAndSanitizeInput(userInput);

       
//將經過淨化的輸入傳遞給模板<i>
        model.addAttribute(
"sanitizedInput", sanitizedInput);

        return
"result";
    }

    private String validateAndSanitizeInput(String input) {
       
// 根據您的要求執行輸入驗證和淨化<i>
       
// 為簡單起見,我們以 HTML 編碼為例<i>
        return org.owasp.encoder.Encode.forHtml(input);
    }
}

在 Spring 應用程式中防止跨站指令碼 (XSS) 的分步實施
以下是在 Spring 應用程式中防止跨站指令碼 (XSS) 的步驟。

第 1 步:提供 securityFilterChain bean
我們必須設定我們的應用程式,透過提供 SecurityFilterChain bean 來傳遞 Content-Security-Policy 標頭:

@Configuration
public class SecurityConf {

    @Bean
    <font>// 配置用於設定安全標頭的 SecurityFilterChain Bean<i>
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception 
    {
        http.headers(headers ->
               
// 配置 XSS 保護標頭<i>
                headers.xssProtection(
                        xss -> xss.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
                ).contentSecurityPolicy(
                       
// 配置內容安全策略,僅允許來自 "self "的指令碼<i>
                        cps -> cps.policyDirectives(
"script-src 'self'")
                ));
        return http.build();
    }
   
// Additional comments can go here for further clarification<i>
}

第2步:新增Maven依賴項
我們可以包含提供額外功能或安全相關技術的依賴項,以提高 Spring 應用程式的安全性並幫助防止跨站指令碼 (XSS)。

<dependency>
    <groupId>org.owasp.encoder</groupId>
    <artifactId>owasp-java-encoder</artifactId>
    <version>2.5.3</version> 
</dependency>

第 3 步:製作針對 XSS 的保護過濾器
為了阻止 XSS 攻擊,XSSFilter 會攔截傳入的請求並執行所需的消毒處理。

import org.owasp.encoder.Encode;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class XSSRequestWrapper extends HttpServletRequestWrapper {

    <font>// 建構函式,用原始請求初始化封裝器<i>
    public XSSRequestWrapper(HttpServletRequest request) {
        super(request);
    }

   
// 重寫方法以獲取引數值,並對每個值進行消毒<i>
    @Override
    public String[] getParameterValues(String parameter) {
       
// 從封裝後的請求中獲取原始引數值<i>
        String[] values = super.getParameterValues(parameter);

       
// If the original values are null, return null<i>
        if (values == null) {
            return null;
        }

       
// 建立一個陣列來儲存經過淨化的值<i>
        int count = values.length;
        String[] sanitizedValues = new String[count];

       
// 遍歷原始值,對每個值進行消毒<i>
        for (int i = 0; i < count; i++) 
        {
            sanitizedValues[i] = sanitizeInput(values[i]);
        }

       
// 返回淨化值陣列<i>
        return sanitizedValues;
    }

   
// 使用 OWASP Java 編碼器對輸入進行消毒的方法<i>
    private String sanitizeInput(String input) {
        return Encode.forHtml(input);
       
}

  • XSSRequestWrapper 類是 HttpServletRequestWrapper 的擴充套件。
  • 它覆蓋了 getParameterValues 函式,並使用 sanitizeInput 方法(該方法使用 OWASP Java Encoder 對 HTML 進行編碼)對每個引數值進行消毒。
  • 透過使用該封裝器,您可以確保在進一步處理之前,對任何潛在的危險輸入進行清理。


步驟 4:設定 XSSFilter
為了避免跨站指令碼攻擊,過濾器會對所有傳入請求應用 XSSFilter 邏輯,其中包括消毒方法。

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebConfig {

    <font>// 配置 XSSFilter 並將其註冊為 bean<i>
    @Bean
    public FilterRegistrationBean<XSSFilter> filterRegistrationBean() {
       
// 為 XSSFilter 建立一個新的 FilterRegistrationBean<i>
        FilterRegistrationBean<XSSFilter> registrationBean = new FilterRegistrationBean<>();

       
// 將 XSSFilter 例項設定為要註冊的過濾器<i>
        registrationBean.setFilter(new XSSFilter());

       
// 指定應用過濾器的 URL 模式<i>
        registrationBean.addUrlPatterns(
"/*");

       
// 返回已配置的過濾器註冊 Bean<i>
        return registrationBean;
    }
}

步驟 5:更新 JSON 淨化封裝器
為了封裝原始請求並覆蓋 getInputStream 函式,以便在進一步處理之前使用 OWASP Java Encoder 對 JSON 主體進行消毒,我們定義了一個擴充套件 HttpServletRequestWrapper 的 XSSRequestWrapper 類。

import com.fasterxml.jackson.databind.ObjectMapper;
import org.owasp.encoder.Encode;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;

public class XSSRequestWrapper extends HttpServletRequestWrapper {

    private final ObjectMapper objectMapper = new ObjectMapper();

    <font>// ... (other methods)<i>

    @Override
    public ServletInputStream getInputStream() throws IOException {
       
// 從封裝請求中獲取原始輸入流<i>
        ServletInputStream originalInputStream = super.getInputStream();

       
// 將整個請求正文讀入字串<i>
        String requestBody = new String(originalInputStream.readAllBytes());

       
// 使用 sanitizeInput 方法對 JSON 主體進行消毒<i>
        String sanitizedBody = sanitizeInput(requestBody);

       
// 建立一個新的 ServletInputStream,其中包含經過消毒的正文<i>
        return new ServletInputStream() {
            private final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
                    sanitizedBody.getBytes()
            );

            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }

            @Override
            public boolean isFinished() {
                return byteArrayInputStream.available() == 0;
            }

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

            @Override
            public void setReadListener(ReadListener readListener) {
               
// No implementation needed for this example<i>
            }
        };
    }

   
// Method to sanitize the input using OWASP Java Encoder<i>
    private String sanitizeInput(String input) {
        return Encode.forHtml(input);
    }
}

  • HttpServletRequestWrapper 由 XSSRequestWrapper 擴充套件。這樣,它就能封裝已經存在的 HttpServletRequest,並透過重寫特定方法來改變其功能。
  • 為了攔截和更改請求的輸入流,getInputStream 函式被重寫。
  • 建立一個 ObjectMapper 例項。該例項可用於進一步處理請求
  • 經過淨化的請求正文包含在一個位元組陣列輸入流(ByteArrayInputStream)中,該輸入流被封裝在一個新的 ServletInputStream 中。

 

相關文章