因此我特地撰寫此篇文章,期望能宣達給網頁開發的新血,告訴大家如何保障自己開發的網站的安全,降低遭到黑帽駭客攻擊的風險。
何謂 Web Security (網頁安全)
泛指針對網頁、網站上的資訊安全,涵蓋程式漏洞、邏輯漏洞、資訊洩漏等。
何謂 XSS (Cross-Site Scripting) 攻擊
XSS 全稱為 Cross-Site Scripting,可中譯為跨網站指令碼攻擊。相信想接觸網站開發的朋友們一定聽過,有一種可以寫在網頁裡,讓瀏覽器執行的程式碼稱為 JavaScript,只要使用 HTML 的 <script> 標籤,就可以在裡面撰寫一些 JavaScript 的程式,讓網頁具有動態、互動效果,甚至能製作遊戲。
雖然 JavaScript 如此方便,但各位是否想過,如果讓任何人可以在你網站上寫入任何 JavaScript 代碼會發生什麼事呢?
那將會非常的危險!因為使用者相信你的網頁是安全的!以為安全進入網站後反而被導向到釣魚網站、甚至被竊取帳號密碼、個人資料,但使用者仍然會傻傻地不知道發生什麼事。
像這樣由惡意人士代入可執行的惡意代碼的手法就被稱為 XSS 攻擊。
至於如何竊取資料?只要插入代碼讓它以 AJAX 方式傳送到攻擊者的伺服器即可。
簡易代碼示範,此網頁具有一個 input 和 button:
當使用者以為輸入密碼是安全的,殊不知當使用者滑鼠點下 Submit 按鈕,會觸發 onfocusout 事件,使密碼被默默寄送到惡意者的伺服器 (此處以不存在的 localhost 進行示範)。
此示範是我本身已經寫好在網頁之中,假如是惡意人士發現可以插入代碼的漏洞,那麼他就可以以「 document.getElementById('id').onfocusout = function() {...} 」之類的方法動態插入事件,或是竊取 cookie 中藏有的重要資料。不僅僅是如此,使用者非常信任你的網站,所以你執行任意指令時使用者幾乎不會注意到,因此還可以拿來進行更惡劣的用途。
目前 XSS 攻擊的種類大致可以分成以下幾種類型:
- Stored XSS (儲存型)
- Reflected XSS (反射型)
- DOM-Based XSS (基於 DOM 的類型)
1. Stored XSS (儲存型)
會被保存在伺服器資料庫中的 JavaScript 代碼引起的攻擊即為 Stored XSS,最常見的就是論壇文章、留言板等等,因為使用者可以輸入任意內容,若沒有確實檢查,那使用者輸入如 <script> 等關鍵字就會被當成正常的 HTML 執行,標籤的內容也會被正常的作為 JavaScript 代碼執行。
像現在各位所使用的巴哈姆特論壇也曾發生過 Stored XSS 的漏洞,詳情可參考此篇文章:
2. Reflected XSS (反射型)
Reflected 是指不會被儲存在資料庫中,而是由網頁後端直接嵌入由前端使用者所傳送過來的內容造成的,最常見的就是以 GET 方法傳送資料給伺服器時,伺服器未檢查就將內容回應到網頁上所產生的漏洞。
此處也用簡單代碼作示範:
功能非常簡單,提供一個 input 讓使用者輸入名字,確定之後,網頁會出現 Hi, XXX 的訊息。
仔細注意網址會發現 GET 參數就是網址上的「 ? 」後面那串,假如我修改成「 ?name=<script>alert(123)</script>」:
這就是因為網頁後端沒有過濾掉惡意字元,直接回傳的內容理所當然會變成正常的代碼執行。
而此手法需透過特定網址點入,因此攻擊者通常會以釣魚手法、社交工程等方式誘騙受害者點入連結,但因為代碼都在網址上,只要細心一點就不容易受害。
3. DOM-Based XSS
了解此種 XSS 類型時,務必事先了解 DOM 是什麼,DOM 全稱為 Document Object Model,用以描述 HTML 文件的表示法,它讓我們可以使用 JavaScript 動態產生完整的網頁,而不必透過伺服器。
因此 DOM-Based XSS 就是指網頁上的 JavaScript 在執行過程中,沒有詳細檢查資料使得操作 DOM 的過程代入了惡意指令。
此處也提供一個簡單的示範:
正常輸入執行後,input 的內容會被代入到 <span id="show_name"> 之中,而網頁本身並不會跳轉。
假如未妥善檢查內容就代入的話,輸入任意的內容都會被建立成有效的 DOM 物件,包含嵌入的代碼也會被執行,此處試著輸入「 <img src=# onerror="alert(123)"> 」。
但這樣除非攻擊者親自到受害者電腦前輸入,否則不可能讓受害者輸入這種惡意代碼。因此通常需要搭配前兩個手法。讓內容保存在伺服器資料庫中、或是以反射型的方式製造出內容,再藉由JavaScript 動態產生有效的 DOM 物件來運行惡意代碼。
如何防範 XSS 攻擊?
1. Stored、Reflected 防範
前兩種 Stored、Reflected 的類型都必須由後端進行防範,除了必要的 HTML 代碼,任何允許使用者輸入的內容都需要檢查,刪除所有「<script>」、「 onerror=」及其他任何可能執行代碼的字串。
若內容只是純字串呈現,基本上只要將以下左欄所有的字元替換成右欄文字就可以杜絕了。
原始字元 | HTML 跳脫字元 (請去除 & 後方的空白) |
< | & lt; |
> | & gt; |
" | & quot; |
' | & #x27; |
/ | & #x2F; |
& | & amp; |

當瀏覽器解析時遇到右欄的文字內容,會認為是左欄的字元,但絕對不會當成代碼的部份,而是純粹的文字,所以顯示上還是會像左邊的字元。
2. DOM-Based 防範
其他兩種類型必須由後端來防範,而 DOM-Based 則必須由前端來防範,但基本上還是跟前面的原則相同。
另外不同的一點就是應該選擇正確的方法、屬性來操作 DOM,譬如前面的示範中會產生漏洞的主要原因是「 document.getElementById('show_name').innerHTML = name; 」中的「 innerHTML 」屬性,此屬性代表插入的內容是合法的 HTML 字串,所以字串會解析成 DOM 物件。
此處的話應該使用「 innerText 」,使用此屬性插入字串時,會被保證作為純粹的文字,也就不可能被插入惡意代碼執行了。
以上就是我的心得和建議提供給網頁開發的新人們,希望能藉此提升各位對網頁安全的意識。
若有其他大大覺得有錯誤的地方也歡迎告知,讓我能及時修正。
另外附上我於板上發表的另一篇文章: