读“NoSQL注入的分析和缓解”之摘录
一、NoSQL攻擊途徑
? ? ?可以大致分為以下5類:
? ? ? 1.重言式。又稱永真式。此類攻擊是在條件語句中注入代碼,使生成的表達式判定結果永遠為真,從而繞過認證或訪問機制。
? ? ? ?2.聯合查詢。聯合查詢是一種眾所周知的SQL注入技術,攻擊者利用一個脆弱的參數去改變給定查詢返回的數據集。聯合查詢最常用的用法是繞過認證頁面獲取數據。在本文中,我們將展示一個攻擊示例,它將通過增加永真的表達式利用布爾OR運算符進行攻擊,從而導致整個語句判定出錯,進行非法的數據獲取。
? ? ? ?3.JavaScript注入。這是一種新的漏洞,由允許執行數據內容中JavaScript的NoSQL數據庫引入的。JavaScript使在數據引擎進行復雜事務和查詢稱為可能。傳遞不干凈的用戶輸入到這些查詢中可以注入任意JavaScript代碼,這會導致非法的數據獲取或篡改。
? ? ? ? 4.背負式查詢。在背負式查詢中,攻擊者通過利用轉義特定字符(比如像回車和換行之類的結束符)插入由數據庫額外執行的查詢,這樣就可以執行任意代碼了。
? ? ? ? 5.跨域違規。HTTP REST APIs是NoSQL數據庫中的一個流行模塊,然而,它們引入了一類新的漏洞,它甚至能讓攻擊者從其他域攻擊數據庫。在跨域攻擊中,攻擊者利用合法用戶和他們的網頁瀏覽器執行有害的操作。在本文中,我們將展示此類跨站請求偽造(CSRF)攻擊形式的違規行為,在此網站信任的用戶瀏覽器將被利用在NoSQL數據庫上執行非法操作。通過把HTML格式的代碼注入到有漏洞的網站護著欺騙用戶進入到攻擊者自己的網站上,攻擊者可以在目標數據庫上執行post動作,從而破壞數據庫。
二、JSON查詢以及數據格式
? ? ? 盡管相對安全,但流行的JSON表述格式仍可受到新類型的注入攻擊。舉例說明MongoDB中的此類攻擊,MongoDB是一個面向文檔的數據庫,已經有多個大型供應商予以采用,其中包括eBay、Foursquare和LinkedIn.
? ? ?在MongoDB中,查詢和數據以JSON格式描述,這在安全方面要優于SQL,因為它是更充分定義的,容易進行加密和解密,而且在每種編程語言中都有不錯的原生實現。像SQL注入那樣對查詢結構的破壞,在JSON結構的查詢中會更難實現。在MongoDB中常見的插入語句應該是這樣的:
db.books.insert({ title: 'The Hobbit', author: 'J.R.R. Tolkien' })? ? ?常見的查詢條件應該是這樣的:
db.books.find({title: 'The Hobbit' })? ? ? 除限制要查詢的字段之外,查詢中還可以包括正則表達式和條件。
三、PHP重言式注入
? ? ?讓我們審視一下架構,一個使用PHP實現后端的Web應用,它將用于查詢數據存儲的請求編碼為JSON格式。讓我們使用一個MongoDB示例去演示數組注入漏洞吧。
? ? ?
? ? ? ? ? 圖3? 使用MongoDB的PHP應用。一個使用PHP實現后端的Web應用,它把用于查詢數據存儲的請求編碼為JSON格式。
? ? ?PHP編碼數組為原生JSON。數組示例如下:?
array('title' => 'The Hobbit', 'author' => 'J.R.R. Tolkien');? ? ? ?將由PHP編碼為以下JSON格式:
{"title": "The Hobbit", "author": "J.R.R. Tolkien"}? ? ? ? 如果一個PHP具有登錄機制,由用戶瀏覽器通過HTTP POST發送過來用戶和密碼,常見的POST URL編碼應該是這樣的:
username=Tolkien&password=hobbit? ? ? ? 后端PHP代碼針對該用戶對它進行處理并查詢MongoDB,如下所示:
db->logins->find(array("username"=>$_ POST["username"], "password"=>$_POST["password"]));? ? ? ?這本身合情合理,然而,PHP針對關聯數組有個內置的機制,這讓攻擊者有機可乘,可發送一下惡意的數據:
username[$ne]=1&password[$ne]=1? ? ? ? ?PHP會把該輸入解析為:
array("username" => array("$[ne] " => 1), "password" => array("$ne" => 1));? ? ? ? 它會編碼為如下MongoDB查詢:
db.logins.find({username: {$ne:1}, password: {$ne:1 })? ? ? ? 因為$ne是MongoDB用來判定條件是否不相等的,所以它會查詢登錄集合中的所有用戶名稱不等于1且密碼也不等于1的記錄。因此,本次查詢將返回登錄集合中的所有用戶。換成SQL的表述法,就等同于以下查詢語句:
SELECT * FROM logins WHERE username <> 1 AND password <> 1? ? ? ? 在這種情況下,漏洞就為攻擊者提供了一個不必有效憑證即可登錄應用的方式。在其他變體中,該漏洞可能會導致非法數據訪問或由無特權的用戶執行特權操作。為緩解這個問題,我們需要轉換從需求中接收的參數為適當類型,在本例中,可使用字符串,如下所示:
db->logins->find( array("username"=>(string)$_ POST["username"], "password"=>(string)$_ POST["password"]));?四、NoSQL聯合查詢注入
? ? ? ?SQL注入漏洞經常是由于未對用戶輸入進行適當編碼而直接拼接查詢造成的。在MongoDB之類的流行數據存儲中,JSON查詢結構使攻擊變得更難了。然而,這并不代表不可能。
? ? ? ?讓我們看一個通過HTTP POST發送用戶名和密碼參數到后端的登錄表單,它通過拼接字符串的方式得到查詢語句。例如,開發人員可能這么做:
string query="{username: '" + post_username + "', password: '" + post_passport + ' "}"? ? ? ? 具有有效輸入時,得到的查詢語句是應該這樣的:
{ username: 'tolkien', password: 'hobbit' }? ? ? ? 但具有惡意輸入時,這個查詢語句會被轉換為忽略密碼的,在無需密碼的情況下登錄用戶賬號。惡意輸入示例如下:
username=tolkien', $or: [ {}, {'a':'a&password=' }],$comment: 'successful MongoDB injection'? ? ? ? ?該輸入會被構建到該查詢中:
{ username: 'tolkien', $or: [ {}, {'a':'a', password '' }], $comment:'successful MongoDB injection' }? ? ? ? ?只要用戶名是正確的,這個查詢就可以成功。轉換成SQL的表述,這個查詢類似于以下語句:
SELECT * FROM logins WHERE username='tolkien' AND (TRUE OR ('a'='a' AND password = ''))? ? ? ? ? 密碼稱為這個查詢多余的一部分,因為()內的條件總為真,所以不會影響到查詢的最終結果。這是怎么發生的呢?以下為拼接出的查詢串,用戶輸入為加粗字體,剩余的文本串為無格式字體:
{ username: 'tolkien', $or: [ {}, {'a':'a',password '' }], $comment: 'successful MongoDB injection' }? ? ? ? ? 這個攻擊在任何只要用戶名正確的情況下都將成功,一般得到個用戶名并不是什么難事。
五、NoSQL JavaScript注入
? ? ? ? NoSQL數據庫中有個共同特性,那就是可以在數據庫引擎中運行JavaScript,從而可以執行復雜的查詢或MapReduce之類的事務。包括MongoDB和CouchDB及其后續的Cloudant和BigCouch等流行的數據庫都允許這么做。如果不干凈的用戶輸入發現這種查詢方式的話,這么執行JavaScript就等于把薄弱面暴露給攻擊者了。例如,設想一個需要JavaScript代碼的復雜事務,包含有不干凈的用戶輸入作為查詢的參數。讓我們看一下它的存儲模型,它保存了一組條目,每個條目具有價格和數量屬性。為得到這些屬性的總數或平均值,開發人員編寫了一個MapReduce函數,它從用戶那里接收數量或價格作為參數,然后進行處理。在PHP中,看起來是如下代碼($param是用戶輸入):
$map="function() {for(var i=0;i<this.items.length; i++) <br> {emit(this.name, this.items[i].$param); }}";<br>$reduce="function(name, sum) {return Array.sum(sum);}";<br>$opt="{out:'totals' }";<br>$db->execute("db.stores.mapReduce($map, $reduce, $opt);");? ? ? ? ? 這段代碼把每個條目按名稱給定的$param合計起來。當時,$param預期是接受數量(amount)或價格(price)的,這段代碼將按預期進行運轉。但是,因為用戶輸入未被定義,所以惡意輸入(它可能包含任意JavaScript)將被執行。
? ? ? ? 看一下如下輸入:
function(kv) {return 1; },{ out:'x'}); db.injection.insert({success:1});return 1;? ? ? ? ? 第一部分的數據會閉合最初的MapReduce函數,然后攻擊者就可以在數據庫上執行想要的JavaScript了(加粗部分)。最終,最后一部分調用一個新的MapReduce以保持被注入代碼的原始語句的平衡。在把會被執行的用戶輸入合并到為字符串后,我們得到以下代碼(注入的用戶輸入加粗顯示):
db.stores.mapReduce(function() { for (var i = 0; i < this.items.length; i++) {emit(this.name, this.items[i].a); } },<br> function(kv) { return 1; }, { out: 'x' }); <br> db.injection.insert({success:1}); return 1; db.stores.mapReduce(function() {<br>{ emit(1,1); } }, function(name, sum) { return Array.sum(sum); }, { out: 'totals' });"? ? ? ? ? ? 這個注入看起來和經典的SQL注入非常相似。防御此類攻擊的一種方式是在數據庫配置中禁止執行JavaScript。如果JavaScript是必需的,那么最好的策略是不使用任何用戶輸入。
六、鍵值對數據存儲
? ? ? 像Memcached、Redis和Tachyon之類的鍵值對存儲是內存數據存儲,旨在加快應用、云架構和平臺以及大數量框架的執行速度。這些平臺考慮的是反復頻繁訪問的數據的存儲和檢索。它們通常處于數據存儲之前,如圖所示。緩存架構經常存儲認證令牌及容器訪問控制列表,對于每個后續的用戶請求必須重新使其生效。
?
? ? ?圖4 分布式內存數據存儲架構。被攻擊的Web服務器使用一個鍵值數據存儲進行快速數據檢索。對數據存儲的查詢是在該Web服務器上通過用戶提供的數據構建出來的。
? ? ?盡管由于鍵值對查詢很簡單所以通常緩存API也非常簡單,但我們發現一個Memcached潛在的注入攻擊手段,那就是基于特定PHP版本的Memcached驅動程序中的漏洞。達成以下條件即可進行攻擊:
1.用作傳遞給換粗nset/get的屬性(例如,value)是來自于用戶請求的信息(例如,HTTP標頭) 2.接收到的字符串未經過處理就發送了 3.緩存的屬性包括將導致查詢執行不同于預期的行為的敏感信息。? ? ? ?如果滿足這些條件,攻擊者就可以注入查詢或操縱查詢邏輯,比如背負式查詢攻擊。
七、背負式查詢
? ? ? 把一個鍵及相應的值加到使用Memcached的數據庫中的一組操作。當從命令行界面調用時,這組函數使用兩行輸入,第一行是:
set <KEY> <FLAG> <EXPIRE_TIME> <LENGTH>,? ? ? ?然后第二行由要保存的數據構成。當PHP配置的函數被調用時,它接收的兩個參數看起來是這樣的:
$memcached->set('key', 'value');? ? ? ?研究人員表示,該驅動程序未能對帶有回車\r(0x0D)和換行的\n(0x0A)的ASCII碼采取措施,導致攻擊者有機會注入包含有鍵參數的新命令行和其他非計劃內的命令道緩存中。
? ? ? ? 看一下如下代碼,其中$param是用戶輸入并作為鍵來作用:
$memcached=new Memcached(); $memcached->addServer('localhost',11211); $memcached->set($param,"some value");? ? ? ? ?攻擊者可以提供以下輸入進行注入攻擊:
"key1 0 3600 4\r\nabcd\r\nset key2 0 3600 4\r\ninject\r\n"? ? ? ? ?在本例中,增加到數據庫中的第一個鍵是具有"some value"值得key1。攻擊者可以增加其他的、非計劃內的鍵到數據庫中,即帶有"inject"值得key2.
? ? ? ? ? 這種注入也可以發生在get命令上。讓我們看一下Memcached主頁上的示例,它以這三行開頭:
Function get_foo(foo_id) foo = memcached_get("foo: " . foo_id)return fooif defined foo? ? ? ? ? 這個示例展示了Memcached的典型用戶,在處理輸入之前首先檢查在數據庫中是不是已經存在了。假設用類似代碼檢查從用過戶那里接受的認證令牌,驗證他們是不是登錄過了,那么就可以通過傳遞一下作為令牌的字符串來利用它:
"random_token\r\nset my_crafted_token 0 3600 4\r\nroot\r\n"? ? ? ?當這個字符串作為令牌傳遞時,數據庫將檢查這個"random_token"是否存在,然后將添加一個具有"root"值的"my_crafted_token"。之后,攻擊者就可以發送具有root身份的my_crafted_token令牌了。
? ? ? ? ? ?可以被這項技術攻擊的其他指令還有:
incr <Key> <Amount> desc <Key> <Amount> delete <Key>? ? ? ? ? ?在此,incr用于增加一個鍵的值,decr用于縮減一個鍵的值,以及delete用于刪除一個鍵。攻擊者也可以用像set和get函數一樣的手段來使用帶來自己鍵參數的這三個函數。
? ? ? ? ? ?攻擊者可以使用多條目函數進行同樣的注入:deleteMulti、getMulti和setMulti,其中每一個鍵字段都可以被注入。
? ? ? ? ? ?回車換行注入可以被用于連接多個get請求。
? ? ? ? ? ?該驅動程序的漏洞已經在PHP 5.5中修復,但不幸的是它已經存在于之前所有的PHP版本中了。按照W3Techs.com對生產系統的PHP版本的統計來看,超過86%的PHP網站使用了比5.5要老的版本,這意味著如果他們使用了Memcached就很容易受到這種注入攻擊。
八、跨域違規
? ? ? ?NoSQL數據庫的另一個常見特點是,他們能夠常常暴露能夠從客戶端應用進行數據庫查詢的HTTP REST API。暴露REST API的數據庫包括MongoDB、CouchDB和HBase。暴露REST API就直接把數據庫暴露給應用了,甚至是僅基于HTML5的應用,因為它不再需要間接的驅動程序了,讓任何編程語言都可以在數據庫上執行HTTP查詢。這種REST API給跨站點請求偽造(CSRF)暴露了數據庫,讓攻擊者繞過了防火墻和其他外圍防御。
?九、緩解
? ? ?鑒于我們在本文中所提到的這些攻擊手段,NoSQL部署中的安全問題的緩解是非常重要的。但不幸的是,應用層的代碼分析不足以確保所有風險都能得以緩解。三個趨勢使該問題將比之前面臨更多的挑戰。首先,云和大數據系統的形成,它們通常會執行多個復雜應用,這些應用使用異構的開源工具和平臺。而這些應用通常由開源社區開發,大多數情況下,未經受過全面的安全性測試。另一個挑戰是伴隨DevOps方法論而形成的現代代碼開發的速度,因為DevOps追求的是縮短開發和生產之間的時間。最后,大多數應用安全測試工具不能與新編程語言的應用保持同步,例如,大多數安全產品不支持Golang、Scala和 Haskel。
總結
以上是生活随笔為你收集整理的读“NoSQL注入的分析和缓解”之摘录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摘录理解LDAP与LDAP注入
- 下一篇: 学习pcre之摘录