Intro
防範XSS、SQL Injection以及驗證資料已經是基本開發流程,但要如何標準化的去做團隊開發就是一門學問。
資料驗證
顧名思義,就是在寫入Datebase之前處理Input資料驗證。
以MVC架構來說,Validator最佳的實踐流程點是在Model/Entity上,也就是Model已定義好驗證規則,所以所有經過此Model寫入的資料都會是經過經過規則驗證通過的,提供絕佳的共用性與嚴謹度。
Yii 2 - Validating Input (Yii 2 透過Model定義Validator實踐開發)
CodeIgniter/Model - Validation (CI擴充框架中,一樣透過Model定義整合Validator實踐開發)
Filter前處理or後處理
以XSS來說,到底要前處理還是後處理? 兩個都沒錯,這全看你後端/資料庫那個欄位到底是定義成Plain Text還是HTML Content。
平均開發上,只要一開始寫資料庫沒特別定義,不外乎都是Plain Text,意即做後處理比較直覺(畢竟過往資料都寫進去了)。
後處理缺點
- 每次在前端(HTML)顯示時都須謹記後處理,漏一個沒處理就中了廣義XSS
前處理缺點
- 因為資料預設就是HTML,所以應付前端不須處理;相反的在需要Plain Text(例如Excel Plain Text)時就需要在後處理反轉回來
- 無法保障資料驗證,因為輸入過濾將影響驗證一致性,例如最大字數通過過濾的不確定性造成不精準
- 遇到
textarea
給值時需要Decode回來 (歸類input,正規給值方式value
或jQueryval()
,用html不標準)
綜合以上,優缺點是一體兩面的,取決於需求。
例如80/20法則,前端顯示開發較多、Plain Text顯示開發較少,那選前處理絕對較省成本,且較嚴謹(畢竟反轉與否不影響安全性),所以依照專案與團隊自行評估即可。
我個人對於Pattern來說會選擇後處理為主,因為儲存資料定義為原始輸入資料(Plain Text)是較合理且彈性的(驗證也一致),畢竟Display部分不只有HTML。當然像CKEidtor content資料庫就必須定義成HTML Content,Editor概念比較特殊是因為Editor又會在UI/UX上反轉一層。
實作範例
前處理
來一個前處理的Case,假設有一個Textarea輸入欄位,可以做的前處理依序為:
- htmlentities/htmlspecialchars
- nl2br
經過以上,使用者任何輸入包含HTML tags都會被過濾成安全的HTML text,其中最後nl2br
會再讓<br>
加入其中,這樣在資料庫中,<
這種就是使用者輸入的跳脫字符,當然<br>
就是系統容許的換行tag。這樣的內容是完全符合Editor儲存內容的,例如往後欄位換成CKEditor,資料庫中的內容定義完全一致,只需要修改後端資料接收流程。
以上的內容經過WEB前端出來,後端可以直接Render在HTML View上,而前端可以使用HTML Ouput。但在還原Input Form時會比較麻煩,例如要將內容使用正規val
打回textarea
內,那內容就需要再反轉(br2nl+decode)回來,然而在前端decode是比encode還不美麗的。
後處理
後端Render View部分如同前處理的流程一樣,只是是套用到每一個Untrust資料輸出:
- htmlentities/htmlspecialchars
- nl2br
前端的話也是在每一個Untrust資料Render時定義處理:
- 使用text/value輸出(如jQuery中的
.text()
)即有效定義格式防止XSS,可多善用 - 套件Datatables中的Renderers有內建Text helper可以定義使用
- 多行輸出會遇到text換行問題,可以參考CSS - white-space實踐,若真的想用JS做字串轉換,可以參考以下函式庫:
總結
XSS可以考慮選後處理架構,接下來的工作就是持續管控好所有Untrusted資料輸出處理