一 前言 問題的存在
從代碼級別上,也就是應用層次上考慮代碼安全的話(也就是不考慮底層的語言本身等問題的漏洞),腳本安全問題就是函數和變量的問題。變量直接或者間接的接收用戶不安全的的輸入,由於php本身的特性,在php中更容易發現這種變量的混亂(很多php程序都用來定義以及初始化以及接收變量,可以直接在程序中使用$id這樣的變量,初始化完全由php的設置來完成,如果稍不注意,就可能導致變量的混亂從而導致攻擊)。
變量接收不安全的輸入之後,沒有做恰當的過濾又用在不同的地方,就可能造成不同的危害。如果直接進入數據庫然後顯示給用戶就會導致跨站腳本攻擊,如果用在 sql語句中就可能導致 Sql注射攻擊,這幾種攻擊都是是與具體的腳本語言無關的,在各種腳本語言裡都可能存在。由於php的變量很靈活,這些有害的變量如果用在一些邏輯語句中,就會導致關鍵代碼的跳過如身份驗證失敗和跳過一些變量的初始化從而導致程序邏輯混亂而產生其他漏洞。如果這個變量用在了危險的函數如include等等當中,當然就會出現文件包含漏洞,出現在fopen函數裡就會可能產生寫文件的漏洞,出現在mysql_query函數中就是 Sql注射漏洞,eval以及preg_replace中可能導致代碼的執行,出現在htmlspecia函數中可能導致出錯而絕對路徑洩露 變量出現的環境決定了它可能的危害。
思考了問題的存在,那麼如何從代碼級別上檢查這種漏洞呢?當然熟悉熟悉php語言是最基本的,也應該是抓住函數和變量,危險的函數裡如果有變量那麼請確定這個變量的來源,是否正確的初始化,初始化之後是否能被用戶注入敏感字符,在進入函數前這些敏感的字符是否得到了徹底的清除。對於代碼審核工作的難點可能就在於對變量來源的確定,這需要對php特性以及你所審核的代碼的熟悉,但也並不是所有的變量的來源都清晰可見,可能一些初始化的代碼並沒有像想象中運行,一些變量裡的東西可能也來自於你並不想他來的地方,還有一些變量可能來自於數據庫或者系統的配置文件,但是很可能數據庫和配置文件在之前就已經被修改,或者在後面不安全的操作了這些變量,這些變量也是不可相信的。下面我們就按照變量與函數的思路來思考腳本代碼的安全。
二 變量來自哪裡?
1 顯示的輸入
叫變量來自哪裡其實也就是說威脅來自哪裡,只是從web上考慮的話,什麼樣的網站最安全?很明顯,那些只提供靜態Html頁面的網站是最安全的,因為這樣的網站不與浏覽者進行任何交互,就好比打劫一個密不透風的銀行,很難實現,但是對於一個大的論壇或者腳本程序就不一樣了,你登陸的時候需要傳遞用戶名和密碼這些變量給服務器,甚至包括你登陸的Ip與浏覽器等等都是程序抓取的對象,抓取一次與服務器交互的過程如發表帖子等等你就發現浏覽器與服務器之間進行的數據傳輸,你可能看得見的包括提交的表單,地址欄參數等等,你看不見的包括Cookie,Http頭都是提交數據也就是變量的地方。這些地方也是服務器處理數據最原始的入口。那麼php程序是如何接受變量的呢?所有提交的變量都被php保存在了一些數組裡,包括
$_GET
$_POST
$_COOKIE
$_FILES
$_SERVER
為了最初的方便與靈活,在php的設置裡有這麼個選項
register_globals
當這個選項為on的時候,上面出現的那些變量都會成為$GLOBALS中的一員,在腳本中都不需要再取得就可以直接使用,並且以
variables_order
的順序覆蓋。很多程序考慮到了register_globals為off的情況,於是在程序初始化的時候使用如下的代碼:
@extract(daddslashes($_POST));
@extract(daddslashes($_GET));
這些代碼起到了register_globals的作用,作用也是將POST和GET的內容釋放出去做為全局變量,但是危險可能更大,後面會提到。