GSS資安電子報0046期【使用NoSQL資料庫就可避免SQL資料隱碼攻擊了嗎?】

alt

撰稿/翻譯整理:叡揚資訊 資訊安全事業處 產品顧問 卓立民alt

引用/參考資料:   
Web App Security: http://www.idontplaydarts.com/2010/07/mongodb-is-vulnerable-to-sql-injection-in-php-at-least/
Fortify blog: http://blog.fortify.com/blog/2011/04/27/NoSQL-no-SQL-injections

每一家企業或多或少會使用資料庫來管理不同的資料,小規模資料量可能使用Microsoft Excel、Access這類的檔案格式,大量資料則可能採用以結構化查詢語言(SQL Structure Query Language)為基礎的關聯式資料庫管理系統(RDBMS Relational Database Management System)。

隨著時間的流逝,資料庫的資料量與日遽增,為了解決資料庫在進行大量資料存取時,所衍生出效能、後續擴充與維護…等問題,於是Google自行研發BigTable,Facebook開發出Cassandra資料庫,微軟Windows雲端平臺使用NoSQL(No Only SQL,翻譯成「不只是SQL」)技術來存取資料。為什麼這些國外大型網站紛紛捨棄存在已久的關聯式資料庫,而改用NoSQL資料庫呢?其原因,不外乎為了提升查詢效能、增加擴充彈性與備援(Redundancy)、降低建置成本。

維基百科(Wikipedia)對NoSQL的解釋是:NoSQL資料庫是一個廣泛的資料庫管理系統(Database Management System)統稱,在某些方面與傳統的關聯式資料庫管理系統有顯著的不同,例如:可能不需要固定的資料表與結構描述(Schema),經常會避免連結(Join)操作以及水平延展。一言以蔽之,NoSQL資料庫泛指哪些非關聯式資料庫、不採用標準SQL語法的資料庫技術,這包括了數十多種不同類型的資料庫系統,例如MongoDB資料庫。NoSQL資料庫大致上可以分成8種,請見表1。

表1

分類

產品名稱

文件(Document)

Lotus Notes

MongoDB

圖形(Graph)

AllegroGraph

DEX

鍵值儲存(Key-value store)

Cassandra

GT.M

託管服務(Hosted services)

BigTable

Oracle Coherence

多值(Multivalue)

OpenQM

OpenInsight

物件(Object)

db4o

GemStone/S

排序鍵值儲存(Ordered key-value store)

Berkeley DB

IBM Informix C-ISAM

表格(Tabular)

BigTable

Hadoop

原組儲存(Tuple store)

Apache River

 

針對NoSQL資料庫是否容易受到類似SQL資料隱碼攻擊的課題,有些迷思出現。畢竟,我們要怎麼在那些不使用SQL的資料庫,進行資料隱碼攻擊呢?以MongoDB為例,沒有採用SQL風格的SELECT語法進行資料庫查詢操作,雖然在該資料庫的常見問題中,也一直強調:「一般來說,於使用MongoDB時,我們並不是用字串來組出查詢指令,所以傳統的SQL資料隱碼攻擊不會是一個問題。」這樣的說法,就技術的角度來說,是對的,但會有些誤導。很多人會曲解其原意為,就所有其他類型的隱碼攻擊而言,這樣是安全的,但卻沒有注意到那句話的關鍵字:「傳統」

讓我們來看看SQL資料隱碼攻擊的手法。SQL結構化查詢語法會包含資料(例如,欄位名稱)以及指令碼(比方說,查詢操作、篩選條件)。而SQL資料隱碼攻擊發生在沒有轉換逸出的中繼(Meta)字元,常見的字元是單引號,駭客即可讓解析器把內涵逸出字元的資料視為指令碼。簡單地說,資料隱碼攻擊是因為語法中,包含了要操作資料庫所需的指令碼,而這些指令碼卻沒有適當地處理逸出的中繼字元。由此我們可以理解為什麼NoSQL資料庫也會有受到此類攻擊的問題。NoSQL資料庫的查詢語言,不論如何,勢必會包含資料與指令碼。只要駭客可以在資料字串中,強制切換資料與邏輯的內容,即會有隱碼攻擊。

換句話說,明確地不使用SQL,並不能讓NoSQL資料庫免於其他來自於本身的查詢語言所引發的隱碼攻擊,而確保其資料庫的安全

來看一下Amazon Web Service的SimpleDB服務,系採用SQL風格的SELECT語法。以下面的程式碼片段為例,應用程式會讓已經通過驗證的客戶,根據他們所指定的產品類別來查詢相關的發票資料:

 

AmazonSimpleDBClient sdbc =

    new AmazonSimpleDBClient(appAWSCredentials);

String query = "select * from invoices where productCategory = '"

    + productCategory + "' and customerID = '"

    + customerID + "' order by '"

    + sortColumn + "' asc";

SelectResult sdbResult = sdbc.select(new SelectRequest(query));

 

應用程式執行時,會把相關的字串填入,例如要查詢客戶編號是12345所採購的筆記型電腦產品之發票資料,並依照價格進行升冪排序,所以上面那段的query 程式碼會變成(換行是為了便於閱讀):

 

select * from invoices

where productCategory = 'Notebook'

and customerID = '12345'

order by 'price' asc

 

假設駭客在產品類別的字串,送出Notebook' or productCategory = \",並且在排序方式中,填入\" order by 'price,此時程式碼會變成什麼樣的結果呢?SimpleDB 會把他們解釋成這樣(換行是為了便於閱讀):

 

select * from invoices

where productCategory = 'Notebook'

or productCategory = "' and customerID = '12345' order by '"

order by 'price' asc

 

請注意,此時customerID = '12345'子句會完全被忽略掉,因此駭客便得以查詢到所有訂購筆記型電腦的客戶發票資料。

使用類似SQL SELECT語法的資料庫,並不是唯一會遭受隱碼攻擊的資料庫。回到先前提到的MongoDB,在Phil的Web App Security部落格Mongodb is vulnerable to SQL injection in PHP at least (http://www.idontplaydarts.com/2010/07/mongodb-is-vulnerable-to-sql-injection-in-php-at-least/) 一文,提到如下的MongoDB 查詢範例:

 

$collection->find(array(

    "username" => $_GET['username'],

    "passwd" => $_GET['passwd']

));

 

如果駭客在網址列,輸入login.php?username=admin&passwd[$ne]=1 這樣的URL,會發生什麼事情?在這個例子中,PHP會自動將傳入的passwd[$ne]=1轉換成關聯陣列(Associative Array),因此組出如下的查詢:

 

$collection->find(array(

    "username" => "admin",

    "passwd" => array("$ne" => 1)

));

 

換句話說,該查詢將傳回每一位密碼不是1的admin使用者,由於admin的密碼不可能是設定為1,因此這個查詢會顯示所有admin的相關資料。

本文所要傳達的重點在於,千萬不要假設軟體是安全的,因為似乎沒有任何軟體會包含我們所熟知的全部攻擊弱點。不論這樣的建議已經被提出多少次,但總還是值得一提再提,那就是:不要相信使用者所輸入的任何資料,永遠要驗證使用者的輸入!

Follow us

立即訂閱以收到最新資安文章