天天看點

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

一個典型的restful的url會用資源名加上資源的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> 

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

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-type為image/png,但是浏覽器推斷出這是一段腳本并且會執行它。  

x-content-type-options就是專門用來解決這個問題的header。通過将其設定為x-content-type-options: nosniff,浏覽器将不再自作主張的推斷http響應内容的類型,而是嚴格按照響應中content-type所指定的類型來解析響應内容。  

x-xss-protection 

避免應用出現跨站腳本漏洞(cross-site scripting,簡稱xss)的最佳辦法是對輸出資料進行正确的編碼,不過除此之外,現如今的浏覽器也自帶了防禦xss的能力。 要開啟浏覽器的防xss功能,隻需要在http響應中加上這個x-xss-protection: 1; mode=block。其中,數字1代表開啟浏覽器的xss防禦功能,mode=block是告訴浏覽器,如果發現有xss攻擊,則直接屏蔽掉目前即将渲染的内容。  

strict-transport-security 

使用tls可以保護資料在傳輸過程中的安全,而在http響應中添加上strict-transport-security這個header,可以告知浏覽器直接發起https請求,而不再像往常那樣,先發送明文的http請求,得到伺服器跳轉指令後再發送後續的https請求。并且,一旦浏覽器接收到這個header,那麼當它發現資料傳輸通道不安全的時候,它會直接拒絕進行任何的資料傳輸,不再允許使用者繼續通過不安全的傳輸通道傳輸資料,以避免資訊洩露。  

會說話的id 

資源id是restful url中很重要的一個組成部分,大多數情況下這類資源id都是用數字來表示的。這在不經意間洩露了業務資訊,而這些資訊可能正是競争對手希望得到的資料。

以檢視使用者資訊的restful url為例:/users/100。由于使用者id是一個按序遞增的數字,是以攻擊者既可以通過id知道目前應用中的使用者規模,也可以分别在月初和月末的時候注冊一個使用者,并對比兩個使用者的id即可知道目前這個月有多少新增使用者。同理,如果訂單号也是按序自增的數字,攻擊者可以了解到一定時間範圍内的訂單量。  

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

傳回多餘的資料 

前後端分離的情況下,兩者之間通常以json作為資料傳輸的主體。有時候可能是為了友善前端代碼處理,也可能是疏忽大意,總之後端api傳回的json資料中包含了遠遠超出前端代碼需要的資料,是以造成資料洩露。  

例如,前端代碼本意是請求訂單資訊,但是後端api傳回的訂單json資料中還包含了很多“有意思”的資料。

上面這個例子裡,訂單資料中包含了使用者資訊,最為關鍵的是連使用者的密碼字段也被包含在内。 

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

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

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

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

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

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

分享者:

馬偉

繼續閱讀