# 網頁安全(Network Security) ## 何謂CORS? ## 何謂CSRF(Cross Site Request Forgery)? 我們知道大部分的網站應用都是採用cookie或session的方式進行登入驗證,當通過登入驗證之後,網站就會給你一個通行證存在cookie或seesion中,代表之後的動作中都不需要重複驗證身分了。這當然是一個好事,沒有人能接受做每一件事都要再輸入一次帳號密碼,但CSRF的攻擊正是鑽了這個機制的漏洞來達到攻擊的目的! ### 實際舉例 我們可以想像cookies就像是每個人身上的筆記本,當你在A銀行登入之後,A銀行在你的筆記本上蓋了個印章,有這個印章之後,接下來三個小時內你的所有動作都不需要重複驗證身分。但你在這三小時內又跑去逛了其他網頁,很不巧的就逛到了駭客B架設的惡意網頁,這個惡意網頁偷偷複製了你的cookie筆記本的印章,跑去打A銀行的轉帳API,請A銀行把你的存款匯10萬元到駭客B自己的帳戶,由於A銀行認印章不認人,所以就接受了這筆匯款請求。 ### 如何防範? 普遍防禦CSRF的方法有兩種: #### 檢查referer欄位 這個方法很簡單,既然攻擊是來自於非銀行網站,那我就確認需求的來源就行了,而http協定中就有一個referer欄位記錄著這個請求是從哪個網站發出來的,只要不是銀行網站發出來的請求,網站這邊一律不接受! 依照這樣的方式,我們可以用快速且低成本的方式來防範CSRF,只是有個問題,就是駭客能否偽造這個referer欄位呢? 如果他也可以偽裝成銀行來源,那用戶就還是會被攻擊。顯然這種方法只能初步防禦CSRF,碰到進階一點的攻擊手法就會再度被破解。 #### 加入驗證token CSRF的核心概念,就是銀行不知道發出請求的人是不是攻擊者,那按照這個思路,只要使用者能提出一個唯一且保密的序號,攻擊者拿不到這個序號,自然就不能偽裝成使用者,而這個序號,就是我們稱的CSRF Token,這個Token是由銀行server產生,並且加密存在session中的,其他人無法仿造,只有透過server給使用者,並在一定時間內刷新。當使用者想做任何交易的時候,銀行server就會請使用者提供CSRF Token,如果不能提供,就代表這次的請求就是攻擊者,那銀行server就不予理會。 ### 結論 CSRF在前幾年都算是非常熱門的攻擊手法, 在OWASP攻擊排名中屢屢上榜,但也因為比較熱門的關係,在諸多開發框架中都已經內建了CSRF的防禦機制,所以慢慢的這種攻擊就有比較退燒的趨勢,但在設計網頁功能時仍需確定設計時有開啟CSRF防護,不然因為一時大意被攻擊可就得不償失了。 ## XSS? **XSS**攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令代碼到網頁,使用戶載入並執行攻擊者惡意製造的網頁程式。這些惡意網頁程式通常是[JavaScript](https://zh.wikipedia.org/wiki/JavaScript "JavaScript"),但實際上也可以包括[Java](https://zh.wikipedia.org/wiki/Java "Java"),[VBScript](https://zh.wikipedia.org/wiki/VBScript "VBScript"),[ActiveX](https://zh.wikipedia.org/wiki/ActiveX "ActiveX"),[Flash](https://zh.wikipedia.org/wiki/Flash "Flash")或者甚至是普通的[HTML](https://zh.wikipedia.org/wiki/HTML "HTML")。攻擊成功後,攻擊者可能得到更高的權限(如執行一些操作)、私密網頁內容、[對談](https://zh.wikipedia.org/wiki/%E4%BC%9A%E8%AF%9D "對談")和[cookie](https://zh.wikipedia.org/wiki/Cookie "Cookie")等各種內容。 ### 過濾特殊字元 避免XSS的方法之一主要是將使用者所提供的內容進行過濾,許多語言都有提供對[HTML](https://zh.wikipedia.org/wiki/HTML "HTML")的過濾: - [PHP](https://zh.wikipedia.org/wiki/PHP "PHP")的`htmlentities()或是htmlspecialchars()`。 - [Python](https://zh.wikipedia.org/wiki/Python "Python")的`cgi.escape()`。 - [ASP](https://zh.wikipedia.org/wiki/ASP "ASP")的`Server.HTMLEncode()`。 - [ASP.NET](https://zh.wikipedia.org/wiki/ASP.NET "ASP.NET")的`Server.HtmlEncode()`或功能更強的[Microsoft Anti-Cross Site Scripting Library](http://msdn.microsoft.com/en-us/library/aa973813.aspx) - [Java](https://zh.wikipedia.org/wiki/Java "Java")的[xssprotect (Open Source Library)](http://code.google.com/p/xssprotect/)。 - [Node.js](https://zh.wikipedia.org/wiki/Node.js "Node.js")的node-validator。 ### 使用HTTP頭指定類型 很多時候可以使用[HTTP頭](https://zh.wikipedia.org/wiki/HTTP%E5%A4%B4%E5%AD%97%E6%AE%B5 "HTTP頭欄位")指定內容的類型,使得輸出的內容避免被作為HTML解析。如在[PHP](https://zh.wikipedia.org/wiki/PHP "PHP")語言中使用以下代碼: ``` <?php header('Content-Type: text/javascript; charset=utf-8'); ?> ``` 即可強行指定輸出內容為文字/JavaScript指令碼(順便指定了內容編碼),而非可以引發攻擊的HTML。 Reference: https://hitcon.org/2015/CMT/download/day1-a-r4.pdf ## SQL Injection? 是發生於應用程式之資料庫層的安全漏洞。簡而言之,是在輸入的字串之中夾帶[SQL](https://zh.wikipedia.org/wiki/SQL "SQL")指令,在設計不良的[程式](https://zh.wikipedia.org/wiki/%E7%A8%8B%E5%BC%8F "程式")當中忽略了檢查,那麼這些夾帶進去的指令就會被[資料庫](https://zh.wikipedia.org/wiki/%E8%B3%87%E6%96%99%E5%BA%AB "資料庫")[伺服器](https://zh.wikipedia.org/wiki/%E4%BC%BA%E6%9C%8D%E5%99%A8 "伺服器")誤認為是正常的SQL指令而執行,因此遭到破壞或是入侵 一個有會員登入功能的網站,都會需要輸入帳號與密碼來進行驗證 而後端程式,如 PHP 就必需支援相關的登入檢查,判定 User 輸入的帳號、密碼是否正確,來確定登入是否成功 ,PHP 執行的 SQL 語法如下,這是一個簡單的 SQL 語法,主要功能是從 members 這個資料表中,取出符合 User 所輸入帳號與密碼的會員資料。 > select * from members where account=\$name and password='\$password' 但若是駭客輸入有特殊字元的帳號:「 '_' or 1=1 /*_ 」,密碼:「任意值」 這時SQL語法就會變成: > select * from members where \_account="" or 1=1 /*_' and password='' 因為「_/*_」在 MySQL 語法中代表註解的意思,所以「/*」後面的字串通通沒有執行,而這句判斷式「_1=1_」永遠成立,駭客就能登入此網站成功。 Reference: https://zh.wikipedia.org/zh-tw/SQL%E8%B3%87%E6%96%99%E9%9A%B1%E7%A2%BC%E6%94%BB%E6%93%8A https://www.puritys.me/docs-blog/article-11-SQL-Injection-%E5%B8%B8%E8%A6%8B%E7%9A%84%E9%A7%AD%E5%AE%A2%E6%94%BB%E6%93%8A%E6%96%B9%E5%BC%8F.html