王保勝, 楊新鋒
(南陽理工學院, 南陽 473000)
隨著研究用腳本語言攻擊站點的人數(shù)的增加,SQL Injection攻擊也倍受關(guān)注,攻擊者利用SQL Injection漏洞可以在幾分鐘內(nèi),甚至幾十秒時間內(nèi),入侵至目標服務(wù)器,獲取未授權(quán)權(quán)限,竊取不公開信息,修改相關(guān)信息,甚至刪除數(shù)據(jù),幾十秒鐘的時間足夠在數(shù)據(jù)庫里面注入數(shù)以萬計的非法數(shù)據(jù)[1-2]。造成這些后果的主要原因就是程序員在編程的失誤或者粗心,然而這些問題完全是可以避免的。國外對于SQL Injection的研究已經(jīng)相當靠前,由于計算機在中國國內(nèi)的發(fā)展時間比較短,國內(nèi)對SQL Injection攻擊這方面的研究比較少[3-4]。
SQL Injection是攻擊者把影響程序正常反應的SQL命令添加到Web表單的輸入?yún)^(qū)域,或者是頁面請求執(zhí)行的字符命令中,而達到對服務(wù)器的欺騙,從而執(zhí)行這個影響程序正常反應的SQL字符命令的攻擊方式[5-6]。
SQL Injection攻擊網(wǎng)站一般都是通過80端口,通過欺騙等手段提交惡意代碼[7]。通過人眼根本無法分辨,甚至通過軟件也無法測試出來,因為SQL Injection訪問網(wǎng)站的方法與正常訪問者的訪問方式并無不同之處,只有管理員查看web日志的時候,才能捕捉一些攻擊信息。
如果軟件或者網(wǎng)站存在SQL Injection漏洞,攻擊者就能夠?qū)?shù)據(jù)庫里面的數(shù)據(jù)進行非法操作,在非法得到一定的服務(wù)器權(quán)限后,攻擊者甚至可以在服務(wù)器中通過欺騙的手段添加木馬,安全性較低的數(shù)據(jù)庫甚至可能被得到服務(wù)器的管理員權(quán)限,這就說明一個數(shù)據(jù)庫的不安全,有可能導致整個站點的內(nèi)容都受到攻擊的威脅。
SQL Injection的本質(zhì)是攻擊者把影響程序正常反應的SQL命令添加到Web表單的輸入?yún)^(qū)域,或者是頁面請求執(zhí)行的字符命令中,而達到對服務(wù)器的欺騙,從而執(zhí)行這個影響程序正常反應的SQL字符命令,并最終將執(zhí)行結(jié)果返回給攻擊者[8-9]。
SQL Injection流程,如圖1所示。
圖1 SQL Injection流程
(1)判斷Web系統(tǒng)腳本語言是使用了哪種計算機語言,找到注入點,確定是否含有SQL Injection漏洞。
(2)判斷Web系統(tǒng)的數(shù)據(jù)庫類型。
(3)判斷一個數(shù)據(jù)庫中表和相應字段的結(jié)構(gòu)。
(4)構(gòu)造sql Injection語句,從而得到表中數(shù)據(jù)內(nèi)容。
(5)查找網(wǎng)站管理的后臺,使用得到的管理員賬號及密碼登錄后臺。
(6)結(jié)合站點其他漏洞,上傳一個Webshell。
(7)對用戶進一步提權(quán),從而得到服務(wù)器的系統(tǒng)權(quán)限,隊整個站點進行非法操作。
(8)刪除侵入痕跡,本地保留侵入方法,以待下一次侵入使用。
下面以管理者和程序員的身份,從防御的角度來談一下如何防止SQL Injection。
在編寫PHP代碼的時候,要充分考慮用戶輸入信息的安全性。
2.1.1 初始化變量
編寫程序的時候一定要初始化函數(shù)里面的變量,代碼如下:
if ($admin){
echo‘恭喜你,登陸成功!’;
include(‘a(chǎn)dmin.php’);
}else{
echo‘你不是管理員,請停止你的非法操作!’;
}
?>
假設(shè)后臺登錄的這個頁面的地址是http://127.0.0.1/login.php,那么在瀏覽器的地址欄里面提交:http://127.0.0.1/login.php?admin =1,顯而易見,問題現(xiàn)了,每個人都是管理員了,只要是進行這個操作的瀏覽者,都可以使用管理員權(quán)限了。
或者將配置文件里面設(shè)置register_global =off這樣就能巧妙地那么就能避免了。重新設(shè)計代碼:
設(shè)計代碼實現(xiàn)后,再重新在地址欄中輸入提交原來的地址:http://127.0.0.1/login.php?admin=1,就會發(fā)現(xiàn),已經(jīng)不能進去了。原因就是在代碼中對變量“$admin”進行了初始化了,令$admin = 0,現(xiàn)在訪問者就無法通過這個漏洞獲取管理員權(quán)限,也沒有辦法進入系統(tǒng)了。由此可以看到,變量的初始化是多么的重要了,變量的初始化,能夠減少漏洞的產(chǎn)生。
$admin=0; //初始化變量
if ($_POST[‘a(chǎn)dmin_user’]&& $_POST[‘a(chǎn)dmin_pass’]){
//假如用戶名和密碼沒有進過處理則不運行代碼
//……
$admin=1;
}else{
$admin=0;
}
if($admin){
echo‘恭喜你,登陸成功!’;
include(‘a(chǎn)dmin.php’);
}else{
echo‘你不是管理員,請停止你的非法操作!’;
}
?>
2.1.2 過濾變量
提交數(shù)據(jù)的方式有兩種,一種是用get,另一種是用post提交。而很多種SQL Injection都是從get提交方式上面著手,尋找利用這方面的漏洞。這些傳值一定會利用SQL語句,打破原來的SQL語句,構(gòu)造新的SQL語句。SQL語句的四大句無外乎select、update、delete和insert,SQL Injection就是利用這4種語句構(gòu)造輸入語句的??梢岳萌缦麓a發(fā)現(xiàn)和避免這些問題:
fuction inject_($sql_str){
return eregi(‘select|insert|update|delete’||
function verify_id($id=null){
//是否為空判斷
if($id){exit(‘沒有提交參數(shù)!’):}
//注入判斷
else if(inject_check($id)){exit(‘提交的參數(shù)非法!’);}
//數(shù)字判斷
else if(!is_numeric($id)){exit(‘提交的參數(shù)非法!’);}
$id=intval($id);//整型化
Returm $id;
}
?>
這樣就能夠進行校驗了,上面的程序代碼可以進一步改寫成:
if (inject_check($_GET[‘id’])){ exit(‘你提交的信息不是正常信息,請檢重新提交合法信息!’);
}else{
//這里調(diào)用了一個過濾的函數(shù);對$id的值進行過濾防止非法數(shù)值的傳入
$id=verifty_id($_GET[‘id’]));
echo‘你提交的信息不是正常信息,進行下一步操作!’;
}
?>
如此設(shè)計代碼,問題似乎都已經(jīng)被解決了。Get傳值的類型解決了,就要考慮與它不同的post傳值的類型了,當然少不了要考慮大批量一起傳輸數(shù)據(jù)。
用戶在提交的數(shù)據(jù)中可能會有對數(shù)據(jù)庫造成影響的字符,比如'_','%'這些字符都具有特殊的意義,那就應該對這些字符進行處理。
在PHP配置文件里面設(shè)置magic_quotes_gpc = off,用戶提交的不符合數(shù)據(jù)庫規(guī)則的數(shù)據(jù),都不會自動的在前面加' '的,這樣就避免了被注入的可能,代碼實現(xiàn)如下:
function str_check($str){
//判斷magic_quotes_gpc是否打開
if(!get_magic_quotes_gpc()){
$str=addslashes($str);//進行過濾
}
$str=str_replace("_","\_",$str);//把‘_’過濾掉
$str=str_replace("%","\%",$str);//把‘%’過濾掉
return $str;
}
?>
然而,在大批量的數(shù)據(jù)面前應該怎么考慮呢?只需要將數(shù)據(jù)進行HTML標記轉(zhuǎn)換,代碼實現(xiàn):
2.2.1 登錄注冊頁面的安全防范
通注冊頁面采用短信驗證或者郵箱驗證,防止水軍注水,緩解服務(wù)器壓力,注冊者使用驗證碼,或者使用郵件里面的鏈接完成對賬號的注冊功能。
注冊的時候,對輸入的賬號進行正則判斷,調(diào)用的正則方程式,而且跟數(shù)據(jù)里的已有賬號作對比,已存在的賬號,不能繼續(xù)注冊。注冊的時候前臺用js代碼進行判斷,目的是減輕服務(wù)器的壓力,同時,PHP代碼也是需要判斷,后臺代碼進行判斷的目的是防止攻擊者屏蔽js腳本,非法傳入數(shù)據(jù)對
function post_check($post){
//判斷magic_quotes_gpc是否為打開
if(!get_magic_quotes_gpc()){
//進行magic_quotes_gpc沒有打開的情況對提交數(shù)據(jù)的過濾
$post=addslashes($post);
}
$post=str_replace("_","\_",$post);//把‘_’過濾掉
$post=str_replace("%","\%",$post);//把‘%’過濾掉
$post=htmlspecialchars($post);//html標記轉(zhuǎn)換
return $post;
}
?>
服務(wù)器的安全產(chǎn)生威脅。注冊和登錄的時候,對輸入的密碼進行HTML標記轉(zhuǎn)換,然后把它的MD5值寫入數(shù)據(jù)庫,或者和數(shù)據(jù)庫里面的值作對比。代碼如下:
$data['username']= $wget['username'];
$wget['password']=htmlspecialchars ($wget['password']);
$data['password']= md5($wget['password']);
郵箱注冊注冊完了,需要驗證,數(shù)據(jù)庫對郵箱注冊的賬號有一個拍段,沒有進過驗證的賬號,是不能夠登錄的。
2.2.2 連接數(shù)據(jù)庫
很過PHP程序員使用@來抑制程序的報錯,代碼如下所示:
$con=@mysql_connect("localhost","peter","abc123";
if(!$con){
die('Could not connect:'.mysql_error()};
}
這種做法不科學,不能真正意義上解決安全問題,登錄數(shù)據(jù)庫可以采用thinkPHP框架的連接數(shù)據(jù)庫的方式,其核心代碼如下:
'DB_TYPE'?'mysql',//數(shù)據(jù)庫數(shù)據(jù)
'DB_HOST'?'127.0.0.1',//服務(wù)器地址
'DB_NAME'?'lagou',//數(shù)據(jù)庫名
'DB_USER'?'root',//用戶名
'DB_PWD'?'',//密碼
'DB_PORT'?'3306',//端口
'DB_PREFIX'?'lg_',//數(shù)據(jù)庫表前綴
'DB_CHARSET'?'utf8',//字符集
'DB_DEBUG'?TRUE,//數(shù)據(jù)庫調(diào)試模式開啟后可以記錄SQL日志3.2.3新增
2.2.3 變量及危險函數(shù)的處理
對于每一個變量,尤其是危險函數(shù)的變量,都可以用“‘’”引起來,然后對變量進行HTML標記轉(zhuǎn)換,這樣就限制住了攻擊者的非法輸入,將用戶輸入的“”,“’”等轉(zhuǎn)換成字符,這樣就避免了SQL漏洞的產(chǎn)生。使用htmlspecialchars()函數(shù)將這些危險符號轉(zhuǎn)換成為字符,不再具有其符號意義。例如登錄時過濾的代碼:
$data['username']= $wget['username'];
$wget['password']=htmlspecialchars ($wget['password']);
$data['password']= md5($wget['password']);
每一個函數(shù)的變量都進行初始化,并且傳值時都進過過濾,保證傳進來的都是安全的數(shù)據(jù)。
正確配置php.ini文件,才能夠確保腳本運行環(huán)境和資源的安全性。
可以使用任何有編輯功能的工具打開“php.ini”文件,對這個文件里面的代碼進行更改,但是要注意的是有些東西更改后會造成數(shù)據(jù)庫的不安全的,不要對這個文件修改的太多,只修改有助于提高數(shù)據(jù)庫安全性的地方就可以了,如圖2所示。
(1)打開PHP配置中的安全模式:
safe_mode = on
(2)用戶組的安全:safe_mode_gid = off
(3)安全模式下執(zhí)行程序主目錄:safe_mode_exec_dir推薦不要去執(zhí)行任何一個程序。
(4)安全模式下的包含文件:
safe_mode_include_dir
(5)控制php腳本能訪問的目錄,使用open_basedir選項,這樣就能夠控制PHP腳本,讓訪問者使其只能訪問它所指定的目錄。
(6)關(guān)閉危險函數(shù):disable_functions = system,passthru,exec,shell_exec,popen,phpinfo
(7)關(guān)閉PHP版本信息:
expose_php = Off
(8)關(guān)閉注冊全局變量選項:
register_globals = Off
(9)打開“magic_quotes_gpc”:
magic_quotes_gpc = On
(10)錯誤信息的控制:
display_errors = Off
(11)錯誤日志:log_errors = On
本文對基于PHP的SQL Injection進行了一定程度上的研究和總結(jié),對于整個數(shù)據(jù)庫安全問題的研究,在各個方面都有所討論。但是,SQL Injection不僅僅出現(xiàn)在PHP中,計算機技術(shù)的迅速發(fā)展,難保系統(tǒng)不會受到更嚴峻的挑戰(zhàn)。本文提出thinkPHP框架的使用可以避免很多出現(xiàn)SQL漏洞的可能性,只需要考慮少量的問題就能夠避免SQL Injection的問題,但是不是所有的PHP開發(fā)人員都會使用框架開發(fā),那些面向過程開發(fā)的程序員面臨的問題更加多,他們需要處理的問題也更加多,這方面還需要繼續(xù)研究。另外一個問題就是對于系統(tǒng)的復雜度是否也對這些解決辦法有所影響,也有待去完善和繼續(xù)探究。
[1] 方自遠.SQL注入攻擊及其檢測防御技術(shù)研究[J].智能計算機與應用,2016,6(6):87-89.
[2] 張志超,王丹,趙文兵,等.一種基于神經(jīng)網(wǎng)絡(luò)的SQL注入漏洞的檢測模型[J].計算機與現(xiàn)代化,2016(10):67-71.
[3] 李虎軍,林學華,張遼寧.SQL注入攻擊與防護探析[J].安徽電子信息職業(yè)技術(shù)學院學報,2016,15(2):58-63.
[4] 李俊鋒.基于Apache+PHP+Mysql網(wǎng)站SQL注入防護探討[J].網(wǎng)絡(luò)空間安全,2016(11):93-95.
[5] 韓宸望,林暉,黃川.基于SQL語法樹的SQL注入過濾方法研究[J].網(wǎng)絡(luò)與信息安全學報,2016,2(11):00113.1-8.
[6] 張慧琳,丁羽,張利華,等.基于敏感字符的SQL注入攻擊防御方法[J].計算機研究與發(fā)展,2016,53(10):2262-2276.
[7] 王苗苗,錢步仁,許瑩瑩,等.基于通用規(guī)則的SQL注入攻擊檢測與防御系統(tǒng)的研究[J].電子設(shè)計工程,2017,25(5):24-29.
[8] 仇善梁.開發(fā)者視角下網(wǎng)站SQL注入漏洞及防范[J].河北軟件職業(yè)技術(shù)學院學報,2016,18(4):52-55.
[9] 趙陽,郭玉翠.新型SQL注入攻擊的研究與防范[J].計算機系統(tǒng)應用,2016,25(6):52-55.