iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 29
3
Modern Web

前端三十 - 成為更好的前端工程師系列 第 29

29. [WEB] 網站常見的資安問題有哪些?

lock

經過一番努力,精心打造的網站眼看就要部屬到正式環境了;但在網站對外之前,你有先仔細思考過你的網站安不安全嗎?在本系列文前面的旅程中,我們討論了許多語言特性、效能優化、技術選型,但如果網站的安全性不足,無法正確保護網站使用者的資料、甚至成為惡意程式的寄生處,那前面堆砌了再多美好也都成枉然。今天就讓我們一起來看看網站常見的資安問題吧。

本系列文已經重新編校彙整編輯成冊,並正式出版囉!
《前端三十:從 HTML 到瀏覽器渲染的前端開發者必備心法》好評販售中!
喜歡我文章內容的讀者們,歡迎您 前往購買 支持!

SQL Injection

在眾多安全性漏洞中,SQL Injection 絕對是最嚴重,也最好處理的一種安全漏洞。發生在對資料庫執行查詢句時,如果將惡意使用者給予的參數直接使用組合在查詢句上,便有機會發生。

舉個例子,假設原本某網站登入驗證的查詢句長這樣:

strSQL = "SELECT * FROM users WHERE (name = '" + userName + "') and (pw = '"+ passWord +"');"

而惡意使用者輸入的參數為:

userName = "1' OR '1'='1";
passWord = "1' OR '1'='1";

由於這邊直接將參數與查詢句做字串連接,合併後,SQL 便成為了這樣:

strSQL = "SELECT * FROM users WHERE (name = '1' OR '1'='1') and (pw = '1' OR '1'='1');"
// 相當於
strSQL = "SELECT * FROM users;"

這樣一來,就形同沒有帳號密碼就可以登入,甚至可以取得整個資料庫的資料結構(SELECT * FROM sys.tables)、任意更改、查詢資料,整個網站的機敏資料就全部外洩了。

解決方法也很簡單,只要透過參數化查詢來避免直接將參數與查詢句組合,並給予適當的輸入檢查、插入跳脫字元、嚴格設定應用程式權限,就能夠有效避免 SQL Injection 囉。

XSS

XSS(Cross-site scripting),也叫做 JavaScript Injection,是現代網站最頻繁出現的問題之一,指的是網站被惡意使用者植入了其他程式碼,通常發生在網站將使用者輸入的內容直接放到網站內容時。例如論壇、討論區等可輸入任意文字的網站,惡意使用者如果寫入 <script>,且前端、後端都沒有針對輸入內容做字元轉換、過濾處理,直接將使用者輸入的字串當成頁面內容的話,就有可能遭到 XSS。

常見的有分成幾個類型:將惡意程式寫入 DB,等資料被讀取出來時就會執行的「儲存型 XSS」,將使用者輸入的內容直接帶回頁面上的「反射型 XSS」,以及利用 DOM 的特性,各種花式執行惡意程式的「DOM-based 型 XSS」。

儲存型及反射型都很好理解,DOM-based 型就非常精彩了;可以參考 OSWAP 整理的 XSS Filter Evasion Cheat Sheet,絕大多數的 XSS 方式,都是透過各個元素的 background-image 屬性,或是元素上的各種事件 callback;其中值得特別留意的是 SVG,由於 SVG 中可以寫入任意 HTML,還可以寫上 onload 事件,若將 SVG 當成一般圖片處理,直接當成網站內容使用,遇到惡意使用者的話,後果不堪設想;開發者們在做上傳圖片時,務必要將 SVG 過濾掉喔!

xss

XSS 的避免方法其實也很簡單,只要在資料輸入/輸出時做好字元轉換,讓惡意程式碼不被執行,而是被解析成字元即可。

關於 XSS,網路上的說明、教材非常多,筆者建議對 XSS 有興趣的讀者,可以到 XSS Challenges 練習看看,學會怎麼攻擊,過程中自然也就能明白如何防守了。

CSRF

先前我們聊過 Cookie & Session,而 CSRF(Cross Site Request Forgery) 就是一種利用 Cookie 及 Session 認證機制的攻擊手法;由於 Session 認證的其實不是使用者,而是瀏覽器,那麼只要透過網頁 DOM 元素可以跨域的機制,對已經得到認證的網站發出請求,就可以假冒使用者,取得不該取得的機敏資料。

例如某間銀行的轉帳 API URL 是這樣:

http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName

而惡意攻擊者如果在網站內塞入 <img />

<img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">

當不知情的使用者瀏覽到惡意攻擊者的網站,<img/> 便會自動送出這個請求,如果使用者在銀行的 Session 尚未過期,這個請求很可能就會被銀行接受,最後便會在使用者本人不知情的情況下,「被」完成轉帳。

這種攻擊方式可以與前述的 XSS 相輔相成,例如在未防範 XSS 的論壇網站中植入 <img/>src 屬性則是取得機敏資訊的 API URL 等等。

解決的方法,主要有幾種:

  • Check Referer:伺服器檢查 Header 中的 Referer 值,也就是檢查請求的來源,如果是來自允許的網站,才會正常執行 API 的功能。
  • CSRF Token:在 Cookie 及請求的資料欄位中都加上 csrftoken,並檢查是否為同一個數值,如果請求來源是自家網站,驗證就會通過;反之,由於外部網站無法在程式碼中取得其他網站的 Cookie,因此無法在請求中帶上 csrftoken
  • SameSite Cookie:在 Cookie 加上 SameSite 屬性,確保 Cookie 僅能在自家網站使用。

更詳細的說明 & 介紹,可以參考 Huli 的 讓我們來談談 CSRF

JSON Hijacking

JSON Hijacking 是利用現代網站大多透過 API 進行前後端資料交換的特性,只要能獲得使用者權限,並呼叫取得資料的 API,再加上改寫原生的 JavaScript 物件,就可以竊取使用者的機敏資訊。

獲得權限的部分如同 CSRF,透過 <script> 可以跨域的特性,直接使用瀏覽器使用者的 Cookie;因此惡意開發者只要在網頁上透過 <script> 呼叫取得資料的 API,當陣列資料回來時,利用 JavaScript 會直接執行的特性,完成資料竊取。

例如:

Object.prototype.__defineSetter__('user',function(obj){
  for(var i in obj) {
    alert(i + '=' + obj[i]);
  }
});

當回傳的資料中包含 user 屬性時,由於 Setter 被透過 Object.prototype.__defineSetter__ 改寫,user 物件中的值便會被全部讀取。

然而 Object.prototype.__defineSetter__ 可以修改原生物件造成的問題,已經早在 ES4 就被修復了,JSON Hijacking
也因此銷聲匿跡好一陣子;但從 ES6 開始又多了 Proxy,JSON Hijacking 又再次成為可能:

<script>
<script>
  Object.setPrototypeOf(
    __proto__,
    new Proxy(__proto__, {
      has: function(target, name) {
        alert(
          name.replace(/./g, function(c) {
            c = c.charCodeAt(0)
            return String.fromCharCode(c >> 8, c & 0xff)
          })
        )
      }
    })
  )
</script>
<script charset="UTF-16BE" src="external-script-with-array-literal"></script>

範例來自 Gareth Heyes - JSON hijacking for the modern web,詳細說明可以參考他的 Blog。

看起來很恐怖,那麼該如何解決呢?除了如同前述的 CSRF Token 外,許多大公司還採用了另一種有趣的解決方式。
例如讀者您可以瀏覽 Facebook 的任意頁面,並打開瀏覽器的開發者工具的 Network 面板,你會看到 Facebook 的 API 回應內容開頭為 for (;;);,這也是利用了 <script> 引入的 JavaScript 會馬上執行的特性,將惡意攻擊者的網站卡在迴圈。

結語

除了今天文中提到的四種常見的網站資安漏洞之外,其實一個網站還有非常多細節要考慮,例如密碼等機敏資訊的儲存不要透過明碼,針對來源IP 做流量限制防止 DOS 等等,但礙於篇幅,及筆者本身對相關知識略顯不足,就不在這篇一併說明了。但還是希望讀者們在進行網站開發時,保持資安意識,盡可能做好基本的防護措施。

以上就是今天的內容啦,明天是最後一天,一起來用經典的問題做個總整理吧!

參考資料

筆者

Gary

半路出家網站工程師;半生熟的前端加上一點點的後端。
喜歡音樂,喜歡學習、分享,也喜歡當個遊戲宅。

相信一切安排都是最好的路。


上一篇
28. [WEB] HTTP 和 HTTPS 的差別是什麼?
下一篇
30. [WEB] 從輸入網址列到渲染畫面,過程經歷了什麼事情?
系列文
前端三十 - 成為更好的前端工程師31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言