記一次安全培訓中對Yii框架資料庫操作層若干介面安全性分析的總結
*本文原創作者:ForrestX386,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載
0×00 前言
給開發的同學們進行不定期的安全培訓是安全建設中不可缺少的一環,也是非常重要的一環。以我的經驗來看,安全培訓或者說安全科普不能教條化,不能書面化,必須得動手實踐,結合例項分析演示給他們看,這樣才能他們信(xing)服(fu),也才能達到預期的效果。本人曾粗淺的分析過Yii框架中常見SQL操作方法原始碼實現,以此向開發同學們闡述哪些SQL方法是安全的,哪些是不安全,使其在開發中編寫更安全的程式碼,也曾取得不錯的效果。近期有空,總結一下當時培訓的內容,於是有了本文。
0×01 CDbCriteria 中的addSearchCondition 為什麼比addCondition 更安全
CDbCriteria中的addSearchCondition 可以防止SQL注入,而addCondition 不能,跟著我一起走進Yii框架的原始碼中一探究竟
1)addCondition 方法原始碼分析
可以看到addCondition 並沒有對傳入的查詢條件進行任何過濾,存在SQL注入風險
2)addSearchCondition 方法原始碼分析
可見addSearchCondition 對傳入的查詢條件(keywords)進行了引數繫結, 繫結的引數是:
self::PARAM_PREFIX.self::$paramCount++
其中 self::PARAM_PREFIX 和 self::$paramCount 的定義如下:
const PARAM_PREFIX=':ycp'; public static $paramCount=0;
所以addSearchCondition 不存在SQL注入風險
與addSearchCondition 同樣內建引數繫結的方法還有compare、addBetweenCondition、addInCondition
小結: addSearchCondition 不存在SQL注入風險,addCondition 存在SQL注入風險
0×02 CActiveRecord->save 方法的安全性分析
在對公司內部程式碼進行安全審計的時候發現很多處都是直接呼叫CActiveRecord->save() 對於前端傳來的資料進行儲存或更新,但未對傳來的資料進行任何過濾,最開始很好奇,這樣難道就不會有注入嗎?(insert 型 or update型),使用SQLMAP一頓狂注之後無果,沒有注入,更加好奇了,於是開始分析其原始碼,探究為啥這樣沒有SQL注入風險,以下是分析過程:
CActiveRecord 中save方法的定義:
首先判斷model 是否需要根據model中定義的rules對屬性值進行校驗(預設是需要校驗的),校驗通過,則判斷是否為新記錄,若是新記錄就插入到資料庫(呼叫insert方法),若不是新記錄,就更新相應的記錄(呼叫update方法),我們以insert 方法為例進行分析(update方法類似):
$builder->createInsertCommand($table,$this->getAttributes($attributes)); 這行程式碼比較關鍵,我們跟一下
程式碼位於 CDbCommandBuilder.php 中的CDbCommandBuilder class中,如下:
程式碼裡面對傳入的引數進行了引數繫結和型別轉換,如下:
$placeholders[]=self::PARAM_PREFIX.$i; $values[self::PARAM_PREFIX.$i]=$column->typecast($value);
而且還利用$column->typecast($value) 進行型別轉換(其中$column為CDbColumnSchema 物件)
typecast 的定義:
小結: 方法在更新資料前(不論是插入還是更新)都會對屬性進行校驗,然後在構造更新SQL的時候進行引數繫結,並且根據列的型別進行型別轉換,所以是可以防止SQL注入的
0×03 CDbCriteria 中的條件屬性limit、offset 安全性分析
經常看到程式碼中如是寫程式碼:
CDbCriteria->limit = xxx; CDbCriteria->offset = xxx
設定好過濾條件之後,呼叫findAll之類的方法進行查詢,這些xxx 沒有任何過濾,這樣到底會不會有SQL注入呢
這裡以呼叫model的findAll 方法為例跟進分析:
findAll 最後會呼叫query,$criteria 是其引數之一, 我們跟一下方法query
query 方法會呼叫createFindCommand方法,我們再跟一下createFindCommand方法
程式碼到最後會呼叫applyLimit方法,這裡是我們需要關注的方法, 我們跟一下applyLimit方法
小結: 我們可以看到 使用者傳入的引數$criteria->limit、$criteria->$offset 已經被做了強制型別轉換,不存在SQL注入
0×04 CDbCriteria 條件屬性order、group、having、join安全性分析
分析過程同0×03,區別在於0×03是applyLimit,而order、group、having、join對應的方法分別如下:
從程式碼中可見,通過 order、group、having、join 屬性傳入的資料沒有任何過濾,存在注入風險
小結: order、group、having、join對傳入的資料均未做任何安全過濾處理,存在SQL注入風險
0×05 總結
個人覺得安全不能停留在嘴上,必須動手實踐,黑哥說的好,整就牛!安全培訓也一樣,必須配以圖文並茂的演示案例才能讓開發們信服,也才能達到預期的培訓效果。大家如果在安全培訓上有更好的經驗心得,也不妨分享一下。
*本文原創作者:ForrestX386,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載