1. 程式人生 > 其它 >常見的網站安全問題

常見的網站安全問題

SQL 注入

在眾多安全性漏洞中,SQL 注入絕對是最嚴重但也是最好處理的一種安全漏洞。在資料庫執行查詢句時,如果將惡意使用者給出的引數直接拼接在查詢句上,就有可能發生。

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

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 注入了。

XSS

XSS(跨站攻擊)也叫JavaScript注入,是現代網站最頻繁出現的問題之一,它指的是網站被惡意使用者植入了其他程式碼,通常發生在網站將使用者輸入的內容直接放到網站內容時。例如論壇、留言板等可以輸入任意文字的網站,惡意使用者如果寫入一小段 <script>,並且前、後端都沒有針對輸入內容做字元轉換和過濾處理,直接把使用者輸入的字串作為頁面內容的話,就有可能遭到 XSS。

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

儲存型及反射型都很好理解,DOM-based 型就非常有意思了;可以參考OSWAP 整理的XSS Filter Evasion Cheat Sheet,絕大多數的 XSS 方式,都是通過各個元素的 background-image 屬性或者元素上的各種事件回撥來實現;其中特別值得注意的是 SVG,由於 SVG 中可以寫入任意html,還可以加上 onload 事件,如果把 SVG 當成普通圖片處理,直接作為網站內容使用,如果遇到惡意使用者的話,後果不堪設想。所以在上線上傳圖片功能時,務必要把 SVG 過濾掉!

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

CSRF

CSRF(跨站請求偽造)是一種利用 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。

解決方法主要有以下幾種:

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

https://www.houdianzi.com/fzlogo/ 福州logo設計

jsON 劫持

jsON 劫持是利用現代網站前後端通過 API 進行資料交換的特性,只要能獲得使用者許可權,並呼叫獲取資料的 API,再加上改寫原生的JavaScript物件,就可以竊取使用者的敏感資訊。

獲得許可權的部分於 CSRF 相同,通過 <script> 可以跨域的特性直接使用瀏覽器使用者的 Cookie;攻擊者只需要在網頁上通過 <script> 呼叫獲取資料的 API 完成對資料的竊取。

例如:

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 劫持也因此銷聲匿跡,但是從 ES6 開始又添加了 Proxy,使 JSON 劫持又再次成為可能:

<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>

看起來很恐怖,那麼該如何解決呢?除了前面所說的 CSRF Token 外,許多大公司還採用了另一種有趣的解決方式。即 API 的響應內容開頭為 for (;;);,這也是利用 了<script> 引入的 JavaScript 會立即執行的特性,把攻擊者的網站卡死在迴圈裡。

總結

除了文中提到的四種常見的網站安全漏洞外,一個網站還有很多細節需要考慮,例如不要用明碼儲存密碼等敏感資訊,針對來源 IP 做流量限制防止 DOS 等等。所以在進行網站開發時要保持安全意識,儘可能做好基本的防護措施。