RESTful架構風格下的4大常見安全問題

伴隨著RESTful架構風格的大量應用微服務架構的流行,一些本來難以察覺到的安全問題也逐漸開始顯現出來。在我經歷過的各種采用RESTful微服務架構風格的應用中,某些安全問題幾乎在每個應用中都會出現。然而它們并非是什么高深的技術難題,只不過是借著微服務的流行而顯得越發突出,這些都可以通過一些安全實踐來避免。本文將一些典型的問題列舉出來,希望能引起開發團隊的注意,幫助他們繞過這些安全問題的“坑”。

1. 遺漏了對資源從屬關系的檢查

一個典型的RESTful的URL會用資源名加上資源的ID編號來標識其唯一性,就像這樣:/users/<USER ID>,例如:/users/100

一般而言用戶只能查看自己的用戶信息,而不允許查看其它用戶的信息。在這種情況下,攻擊者很可能會嘗試把這個URL里面的USER ID從100修改為其他數值,以期望應用返回指定用戶的信息。不過由于這個安全風險太顯而易見,絕大多數應用都會對當前請求者的身份進行校驗,看其是否是編號為100的用戶,校驗成功才返回URL中指定的用戶信息,否則會拒絕當前請求。

對于URL中只出現一個資源的情況,絕大多數應用都已經做了安全防御,然而重災區出現在URL中包含多個資源的時候。

以用戶查看訂單的RESTful URL為例:/users/100/orders/280010,應用只檢查了當前請求發起者是否是編號為100的用戶,以及編號為280010的訂單是否存在,有很大的概率沒有檢查URL中的訂單和用戶之間的從屬關系。其結果是,攻擊者可以通過修改URL中的訂單編號,從而遍歷系統中的所有訂單信息,甚至對不屬于他/她的訂單發起操作,例如取消訂單。

上面的例子中只有兩個資源,如果URL中資源數量繼續增加,這種從屬關系校驗缺失的情況只會更加普遍。

解決這一問題的方法極其簡單,只要發現URL里面出現了兩個或者兩個以上的資源,就像下面這樣:

/ResourceA/<ResourceA Id>/ResourceB/<ResourceB Id>/ResourceC/<ResourceC Id>

在對資源進行操作之前,就得先檢查這些資源之間的從屬關系,以確保當前請求具有相關的訪問、操作權限。

2. HTTP響應中缺失必要的 Security Headers

HTTP中有一些和安全相關的Header,通過對它們的合理使用,可以使得應用在具備更高的安全性的同時,并不會顯著增大開發者的工作負擔,有著“低成本高收益”的效果。不過絕大多數情況下,這些Header是默認關閉的,因此很多應用中也就缺失了這些Security Headers。一些典型的Security Headers如下:

X-Frame-Options
為了防止應用遭受點擊劫持攻擊,可以使用X-Frame-Options: DENY明確告知瀏覽器,不要把當前HTTP響應中的內容在HTML Frame中顯示出來。

X-Content-Type-Options
在瀏覽器收到HTTP響應內容時,它會嘗試按照自己的規則去推斷響應內容的類型,并根據推斷結果執行后續操作,而這可能造成安全問題。例如,一個包含惡意JavaScript代碼的HTTP響應內容,雖然其Content-Typeimage/png,但是瀏覽器推斷出這是一段腳本并且會執行它。

X-Content-Type-Options就是專門用來解決這個問題的Header。通過將其設置為X-Content-Type-Options: nosniff,瀏覽器將不再自作主張的推斷HTTP響應內容的類型,而是嚴格按照響應中Content-Type所指定的類型來解析響應內容。

X-XSS-Protection
避免應用出現跨站腳本漏洞(Cross-Site Scripting,簡稱XSS)的最佳辦法是對輸出數據進行正確的編碼,不過除此之外,現如今的瀏覽器也自帶了防御XSS的能力。

要開啟瀏覽器的防XSS功能,只需要在HTTP響應中加上這個Header:X-XSS-Protection: 1; mode=block。其中,數字1代表開啟瀏覽器的XSS防御功能,mode=block是告訴瀏覽器,如果發現有XSS攻擊,則直接屏蔽掉當前即將渲染的內容。

Strict-Transport-Security
使用TLS可以保護數據在傳輸過程中的安全,而在HTTP響應中添加上Strict-Transport-Security這個Header,可以告知瀏覽器直接發起HTTPS請求,而不再像往常那樣,先發送明文的HTTP請求,得到服務器跳轉指令后再發送后續的HTTPS請求。并且,一旦瀏覽器接收到這個Header,那么當它發現數據傳輸通道不安全的時候,它會直接拒絕進行任何的數據傳輸,不再允許用戶繼續通過不安全的傳輸通道傳輸數據,以避免信息泄露。

3. 不經意間泄露的業務信息

會說話的ID
資源ID是RESTful URL中很重要的一個組成部分,大多數情況下這類資源ID都是用數字來表示的。這在不經意間泄露了業務信息,而這些信息可能正是競爭對手希望得到的數據。

以查看用戶信息的RESTful URL為例:/users/100。由于用戶ID是一個按序遞增的數字,因此攻擊者既可以通過ID知道目前應用中的用戶規模,也可以分別在月初和月末的時候注冊一個用戶,并對比兩個用戶的ID即可知道當前這個月有多少新增用戶。同理,如果訂單號也是按序自增的數字,攻擊者可以了解到一定時間范圍內的訂單量。

這類ID并不會給應用造成任何技術上的威脅,只是通過ID泄露出來的信息對于你的業務而言可能非常敏感。解決辦法是不使用按序遞增的數字作為ID,而是使用具有隨機性、唯一性、不可預測性的值作為ID,最常見的做法就是使用UUID。

返回多余的數據
前后端分離的情況下,兩者之間通常以JSON作為數據傳輸的主體。有時候可能是為了方便前端代碼處理,也可能是疏忽大意,總之后端API返回的JSON數據中包含了遠遠超出前端代碼需要的數據,因此造成數據泄露。

例如,前端代碼本意是請求訂單信息,但是后端API返回的訂單JSON數據中還包含了很多“有意思”的數據。

{
    "id": 280010, 
    "orderItems": [...], 
    "user": {
        "id": 100, 
        "password": "91B4E3E45B2465A4823BB5C03FF81B65"
    },
    ...
}

上面這個例子里,訂單數據中包含了用戶信息,最為關鍵的是連用戶的密碼字段也被包含在內。

解決辦法顯而易見,在給前端返回數據之前,將這些敏感的、前端并不需要的數據過濾掉。技術上實現起來易如反掌,但是真正難的地方在于讓整個應用都嚴格的按照這樣的方式來處理JSON數據,確保沒有任何遺漏之處。

4. API缺乏速率限制的保護

先看一個例子。用戶注冊時發送短信驗證碼的API,由于沒有做速率限制,使得攻擊者可以用一段腳本不斷的請求服務器發送短信驗證碼,導致在短時間內耗盡短信發送配額,或者造成短信網關擁擠等等后果。

受傷的不僅僅是發送短信的API,其他一些比較敏感的API如果缺乏請求速率限制的保護,同樣也會遭遇安全問題。例如用戶登錄的API缺乏速率限制的話,攻擊者可以利用其進行用戶名密碼暴力破解,再例如某些大量消耗服務器資源的API如果缺乏速率限制,攻擊者可以利用其發起拒絕式攻擊。

解決這類安全問題的原則就是對API請求的速率進行適當的限制。具體的做法有很多,最典型的例子就是使用圖片驗證碼,其他的做法還有利用Redis的Expire特性對請求速率進行統計判斷,甚至借助運維的力量(例如網絡防火墻)來共同進行防御等等。

總結

開發出一個具備足夠安全性的應用不是件容易的事情,本文中提到的只是RESTful架構風格下,眾多安全問題中比較典型的一部分而已。之所以會有這些問題,其本質原因在于應用開發過程中,開發團隊的注意力集中在業務功能的實現上,應用安全性相關的需求沒有得到足夠的明確和重視。

如果你不想被這些安全問題所困擾,建議通過在應用開發過程中引入威脅建模、在用戶故事卡中設立安全驗收標準、進行安全代碼審查等一系列安全實踐,盡可能從源頭上規避這些問題。


更多精彩洞見,請關注微信公眾號:思特沃克

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容