Recca Chao 的 gitHub page

推廣網站開發,包含 Laravel 和 Kotlin 後端撰寫、自動化測試、讀書心得等。Taiwan Kotlin User Group 管理員。

View on GitHub

翻譯自

https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cryptographic_Storage_Cheat_Sheet.md


輸入驗證速查表

簡介

本文旨在提供清晰、簡單、可操作的指導,以在應用程式中提供輸入驗證安全功能。

輸入驗證的目標

輸入驗證是為了確保只有格式正確的資料進入資訊系統的工作流程,防止格式錯誤的資料持續存在於資料庫中並觸發各種下游元件的故障。輸入驗證應該在資料流程中盡早進行,最好是在從外部方接收到資料時就進行。

所有潛在不受信任來源的資料都應該經過輸入驗證,包括不僅僅是面向互聯網的網頁客戶端,還包括來自外部網絡的後端供應源,來自供應商、合作夥伴、供應商或監管機構的數據,這些數據可能會被單獨入侵並開始發送格式錯誤的數據。

輸入驗證不應該被用作防止XSSSQL Injection和其他攻擊的主要方法,這些攻擊在各自的速查表中有所涵蓋,但如果正確實施,輸入驗證可以顯著有助於減少它們的影響。

輸入驗證策略

應在語法和語義層面上應用輸入驗證:

建議盡早在處理用戶(攻擊者)請求時防止攻擊。輸入驗證可用於在應用程式處理之前檢測未經授權的輸入。

實施輸入驗證

可以使用任何有效執行語法和語義正確性的編程技術來實施輸入驗證,例如:

允許清單 vs 拒絕清單

使用拒絕清單驗證來嘗試檢測可能危險的字符和模式(例如撇號 ' 字元、字符串 1=1<script> 標籤)是一個常見的錯誤,但這是一個嚴重有缺陷的方法,因為攻擊者可以輕易繞過此類過濾器。

此外,這樣的過濾器經常阻止授權的輸入,例如 O'Brian,其中 ' 字元是完全合法的。有關跨站腳本攻擊避免的更多信息,請參見此維基頁面

雖然拒絕清單可以作為捕捉一些常見惡意模式的額外防禦層,但不應依賴它作為主要方法。允許清單仍然是預防潛在有害輸入的更堅固和安全的方法。

對於用戶提供的所有輸入字段,允許清單驗證是適當的。允許清單驗證涉及確定什麼是被授權的,並根據定義,其他所有內容都是未經授權的。

如果是結構化的資料,例如日期、社會安全號碼、郵遞區號、電子郵件地址等,開發人員應該能夠定義非常強大的驗證模式,通常基於正則表達式,用於驗證此類輸入。

如果輸入欄位來自一組固定的選項,例如下拉列表或單選按鈕,則輸入需要與用戶一開始提供的值中的一個完全匹配。

驗證自由格式的 Unicode 文本

自由格式文本,特別是包含 Unicode 字元的文本,由於需要允許的字符範圍相對較大,被認為難以驗證。

這也是自由格式文本輸入突顯了正確上下文感知輸出編碼的重要性,並清楚地表明輸入驗證不是防範跨站腳本攻擊的主要保障。如果您的用戶想在評論欄中輸入撇號 ' 或小於號 <,他們可能有非常合理的理由,應用程序的工作是在整個數據的生命週期中正確處理它。

自由格式文本輸入的主要輸入驗證手段應該是:

參考資料:

正則表達式(Regex)

開發正則表達式可能很複雜,遠超出了這份速查表的範圍。

有很多關於如何編寫正則表達式的資源在網上,包括這個網站OWASP 驗證正則表達式存儲庫

在設計正則表達式時,要注意正則表達式拒絕服務(ReDoS)攻擊。這些攻擊會導致使用設計不良的正則表達式的程序運行非常緩慢,並長時間使用 CPU 資源。

總結一下,輸入驗證應該:

允許列表正則表達式示例

驗證美國郵政編碼(5 位數字加可選的 -4)

^\d{5}(-\d{4})?$

驗證從下拉菜單中選擇美國州名

^(AA|AE|AP|AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|
HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE|
NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|
TX|UT|VT|VI|VA|WA|WV|WI|WY)$

Java 正則表達式使用示例:

示例使用正則表達式驗證參數 “zip”。

private static final Pattern zipPattern = Pattern.compile("^\d{5}(-\d{4})?$");

public void doPost( HttpServletRequest request, HttpServletResponse response) {
  try {
      String zipCode = request.getParameter( "zip" );
      if ( !zipPattern.matcher( zipCode ).matches() ) {
          throw new YourValidationException( "Improper zipcode format." );
      }
      // do what you want here, after its been validated ..
  } catch(YourValidationException e ) {
      response.sendError( response.SC_BAD_REQUEST, e.getMessage() );
  }
}

一些允許列表驗證器也已經在各種開源套件中預定義,您可以利用這些驗證器。例如:

客戶端 vs 伺服器端驗證

在應用程序的功能處理任何數據之前,必須在伺服器端實施輸入驗證,因為任何在客戶端執行的基於 JavaScript 的輸入驗證都可能被禁用 JavaScript 的攻擊者繞過或使用網絡代理。實施客戶端基於 JavaScript 的驗證以提升用戶體驗和伺服器端驗證以確保安全是推薦的方法,利用各自的優勢。

驗證豐富用戶內容

驗證用戶提交的豐富內容非常困難。有關更多信息,請參閱有關使用專為此工作設計的庫對 HTML 標記進行消毒的 XSS 速查表Cross_Site_Scripting_Prevention_Cheat_Sheet.md

防止跨網站指令碼攻擊(XSS)和內容安全策略

所有受控用戶數據在返回 HTML 頁面時必須進行編碼,以防止惡意數據的執行(例如 XSS)。例如 <script> 將被返回為 &lt;script&gt;

編碼的類型取決於用戶控制數據插入的頁面上下文。例如,對於放置在 HTML 主體中的數據,HTML 實體編碼是適當的。然而,放置在腳本中的用戶數據需要 JavaScript 特定的輸出編碼。

有關 XSS 預防的詳細信息請參見:OWASP XSS Prevention Cheat Sheet

文件上傳驗證

許多網站允許用戶上傳文件,例如個人資料圖片等。本節有助於安全地提供該功能。

查看 文件上傳防範小抄

上傳驗證

上傳存儲

公開提供上傳內容

注意特定檔案類型

上傳功能應該使用允許清單方法,僅允許特定檔案類型和副檔名。然而,重要的是要注意以下檔案類型,如果允許,可能會導致安全漏洞:

圖片上傳驗證

電子郵件地址驗證

語法驗證

電子郵件地址的格式由 RFC 5321 定義,比大多數人意識到的要複雜得多。例如,以下都被認為是有效的電子郵件地址:

使用正則表達式正確解析電子郵件地址的有效性非常複雜,儘管有許多有關正則表達式的 公開文件

最大的注意事項是,儘管 RFC 為電子郵件地址定義了一個非常靈活的格式,但大多數現實世界的實作(例如郵件伺服器)使用的是一個更受限制的地址格式,這意味著它們將拒絕技術上有效的地址。儘管這些地址在技術上是正確的,但如果您的應用程式無法實際向這些地址發送郵件,則這些地址幾乎沒有用處。

因此,驗證電子郵件地址的最佳方法是進行一些基本的初始驗證,然後將地址傳遞給郵件伺服器,如果郵件伺服器拒絕該地址,則捕獲異常。這意味著應用程式可以確信其郵件伺服器可以向接受的任何地址發送郵件。初始驗證可能如下:

語義驗證

語義驗證是關於確定電子郵件地址是否正確和合法的。最常見的方法是向用戶發送一封電子郵件,要求他們點擊郵件中的鏈接,或輸入已發送給他們的代碼。這提供了一個基本的保證:

發送給用戶以證明所有權的鏈接應包含一個標記,該標記:

在驗證電子郵件地址的所有權後,用戶應該被要求通過應用程序上的常規機制進行身份驗證。

一次性電子郵件地址

在某些情況下,用戶在應用程序註冊時可能不想提供他們的真實電子郵件地址,而是提供一個一次性電子郵件地址。這些是公開可用的地址,用戶無需進行身份驗證,通常用於減少用戶主要電子郵件地址收到的垃圾郵件量。

阻止一次性電子郵件地址幾乎是不可能的,因為有許多網站提供這些服務,每天都會創建新的域。有一些公開可用的已知一次性域名列表和商業列表,但這些列表總是不完整的。

如果使用這些列表來阻止使用一次性電子郵件地址,則應向用戶顯示一條消息,解釋為什麼他們被阻止(儘管他們可能只是簡單地尋找另一個一次性提供者,而不是提供他們的合法地址)。

如果必須阻止一次性電子郵件地址,則應僅允許從特定允許的電子郵件提供者進行註冊。但是,如果這包括像Google或Yahoo這樣的公共提供者,用戶可以簡單地在這些提供者那裡註冊自己的一次性地址。

子地址

子地址允許用戶在電子郵件地址的本地部分(在 @ 符號之前)指定一個 標籤,這將被郵件服務器忽略。例如,如果該 example.org 域支持子地址,則以下電子郵件地址是等效的:

許多郵件提供者(如Microsoft Exchange)不支持子地址。最著名支持子地址的提供者是Gmail,儘管還有許多其他提供者也支持。

一些用戶將為他們在每個註冊的網站使用不同的 標籤,這樣如果他們開始收到垃圾郵件到其中一個子地址,他們可以識別哪個網站洩漏或出售了他們的電子郵件地址。

因為這可能允許使用者使用單一電子郵件地址註冊多個帳戶,一些網站可能希望阻止子地址功能,方法是刪除 +@ 之間的所有內容。一般來說,這不被建議,因為這暗示網站擁有者可能不知道子地址功能,或者希望防止使用者在洩漏或出售電子郵件地址時識別他們。此外,這可以輕鬆地被繞過,方法是使用一次性電子郵件地址,或者簡單地在可信任的提供者處註冊多個電子郵件帳戶。

參考資料