PHP開(kāi)發(fā)中常見(jiàn)的安全問(wèn)題詳解和解決方法(如Sql注入、CSRF、Xss、CC等)
淺談Php安全和防Sql注入,防止Xss攻擊,防盜鏈,防CSRF
前言:
首先,筆者不是web安全的專(zhuān)家,所以這不是web安全方面專(zhuān)家級(jí)文章,而是學(xué)習(xí)筆記、細(xì)心總結(jié)文章,里面有些是我們phper不易發(fā)現(xiàn)或者說(shuō)不重視的東西。所以筆者寫(xiě)下來(lái)方便以后查閱。在大公司肯定有專(zhuān)門(mén)的web安全測(cè)試員,安全方面不是phper考慮的范圍。但是作為一個(gè)phper對(duì)于安全知識(shí)是:“知道有這么一回事,編程時(shí)自然有所注意”。
目錄:
1、php一些安全配置
(1)關(guān)閉php提示錯(cuò)誤功能
(2)關(guān)閉一些“壞功能”
(3)嚴(yán)格配置文件權(quán)限。
2、嚴(yán)格的數(shù)據(jù)驗(yàn)證,你的用戶(hù)不全是“好”人
2.1為了確保程序的安全性,健壯性,數(shù)據(jù)驗(yàn)證應(yīng)該包括內(nèi)容。
2.2程序員容易漏掉point或者說(shuō)需要注意的事項(xiàng)
3、防注入
3.1簡(jiǎn)單判斷是否有注入漏洞以及原理
3.2常見(jiàn)的mysql注入語(yǔ)句
(1)不用用戶(hù)名和密碼
(2)在不輸入密碼的情況下,利用某用戶(hù)
(3)猜解某用戶(hù)密碼
(4)插入數(shù)據(jù)時(shí)提權(quán)
(5)更新提權(quán)和插入提權(quán)同理
(6)惡意更新和刪除
(7)union、join等
(8)通配符號(hào)%、_
(9)還有很多猜測(cè)表信息的注入sql
33防注入的一些方法
2.3.1 php可用于防注入的一些函數(shù)和注意事項(xiàng)。
2.3.2防注入字符優(yōu)先級(jí)。
2.3.3防注入代碼
(1)參數(shù)是數(shù)字直接用intval()函數(shù)
(2)對(duì)于非文本參數(shù)的過(guò)濾
(3)文本數(shù)據(jù)防注入代碼。
(4)當(dāng)然還有其他與addslashes、mysql_escape_string結(jié)合的代碼。
4、防止xss攻擊
4.1Xss攻擊過(guò)程
4.2常見(jiàn)xss攻擊地方
4.3防XSS方法
5、CSRF
5.1簡(jiǎn)單說(shuō)明CSRF原理
5.2防范方法
6、防盜鏈
7、防拒CC攻擊
1、php一些安全配置
(1)關(guān)閉php提示錯(cuò)誤功能
在php.ini 中把display_errors改成
或在php文件前加入
1)使用error_reporting(0);失敗的例子:
A文件代碼:
error_reporting(0);
echo 555
echo 444;
?>
錯(cuò)誤:
2)使用error_reporting(0);成功的例子:
a文件代碼:
<?php
error_reporting(0);
include("b.php");
?>
b文件代碼:
<?php
echo 555
echo 444;
?>
這是很多phper說(shuō)用error_reporting(0)不起作用。第一個(gè)例子A.php里面有致命錯(cuò)誤,導(dǎo)致不能執(zhí)行,不能執(zhí)行服務(wù)器則不知有這個(gè)功能,所以一樣報(bào)錯(cuò)。
第二個(gè)例子中a.php成功執(zhí)行,那么服務(wù)器知道有抑制錯(cuò)誤功能,所以就算b.php有錯(cuò)誤也抑制了。
ps:抑制不了mysql錯(cuò)誤。
(2)關(guān)閉一些“壞功能”
1)關(guān)閉magic quotes功能
在php.ini 把magic_quotes_gpc = OFF
避免和addslashes等重復(fù)轉(zhuǎn)義
2)關(guān)閉register_globals = Off
在php.ini 把register_globals = OFF
在register_globals = ON的情況下
地址欄目:http://www.dbjr.com.cn?bloger=benwin
<?php
//$bloger = $_GET['bloger'] //因?yàn)閞egister_globals = ON 所以這步不用了直接可以用$bloger
echo $bloger;
?>
這種情況下會(huì)導(dǎo)致一些未初始化的變量很容易被修改,這也許是致命的。所以把register_globals = OFF關(guān)掉
(3)嚴(yán)格配置文件權(quán)限。
為相應(yīng)文件夾分配權(quán)限,比如包含上傳圖片的文件不能有執(zhí)行權(quán)限,只能讀取
2、嚴(yán)格的數(shù)據(jù)驗(yàn)證,你的用戶(hù)不全是“好”人。
記得筆者和一個(gè)朋友在討論數(shù)據(jù)驗(yàn)證的時(shí)候,他說(shuō)了一句話:你不要把你用戶(hù)個(gè)個(gè)都想得那么壞!但筆者想說(shuō)的這個(gè)問(wèn)題不該出現(xiàn)在我們開(kāi)發(fā)情景中,我們要做的是嚴(yán)格驗(yàn)證控制數(shù)據(jù)流,哪怕10000萬(wàn)用戶(hù)中有一個(gè)是壞用戶(hù)也足以致命,再說(shuō)好的用戶(hù)也有時(shí)在數(shù)據(jù)input框無(wú)意輸入中文的時(shí),他已經(jīng)不經(jīng)意變“壞”了。
2.1為了確保程序的安全性,健壯性,數(shù)據(jù)驗(yàn)證應(yīng)該包括
(1) 關(guān)鍵數(shù)據(jù)是否存在。如刪除數(shù)據(jù)id是否存在
(2) 數(shù)據(jù)類(lèi)型是否正確。如刪除數(shù)據(jù)id是否是整數(shù)
(3) 數(shù)據(jù)長(zhǎng)度。如字段是char(10)類(lèi)型則要strlen判斷數(shù)據(jù)長(zhǎng)度
(4) 數(shù)據(jù)是否有危險(xiǎn)字符
數(shù)據(jù)驗(yàn)證有些人主張是把功能完成后再慢慢去寫(xiě)安全驗(yàn)證,也有些是邊開(kāi)發(fā)邊寫(xiě)驗(yàn)證。筆者偏向后者,這兩種筆者都試過(guò),然后發(fā)現(xiàn)后者寫(xiě)的驗(yàn)證相對(duì)健壯些,主要原因是剛開(kāi)發(fā)時(shí)想到的安全問(wèn)題比較齊全,等開(kāi)發(fā)完功能再寫(xiě)時(shí)有兩個(gè)問(wèn)題,一個(gè)phper急于完成指標(biāo)草草完事,二是確實(shí)漏掉某些point。
2.2程序員容易漏掉point或者說(shuō)需要注意的事項(xiàng):
(1) 進(jìn)庫(kù)數(shù)據(jù)一定要安全驗(yàn)證,筆者在廣州某家公司參與一個(gè)公司內(nèi)部系統(tǒng)開(kāi)發(fā)的時(shí)候,見(jiàn)過(guò)直接把$_POST數(shù)據(jù)傳給類(lèi)函數(shù)classFunctionName($_POST),理由竟然是公司內(nèi)部使用的,不用那么嚴(yán)格。暫且不說(shuō)邏輯操作與數(shù)據(jù)操控耦合高低問(wèn)題,連判斷都沒(méi)判斷的操作是致命的。安全驗(yàn)證必須,沒(méi)任何理由推脫。
(2) 數(shù)據(jù)長(zhǎng)度問(wèn)題,如數(shù)據(jù)庫(kù)建表字段char(25),大多phper考慮到是否為空、數(shù)據(jù)類(lèi)型是否正確,卻忽略字符長(zhǎng)度,忽略還好更多是懶于再去判斷長(zhǎng)度。(這個(gè)更多出現(xiàn)在新手當(dāng)中,筆者曾經(jīng)也有這樣的思想)
(3) 以為前端用js判斷驗(yàn)證過(guò)了,后臺(tái)不需要判斷驗(yàn)證。這也是致命,要知道偽造一個(gè)表單就幾分鐘的事,js判斷只是為了減少用戶(hù)提交次數(shù)從而提高用戶(hù)體驗(yàn)、減少http請(qǐng)求減少服務(wù)器壓力,在安全情況下不能防“小人”,當(dāng)然如果合法用戶(hù)在js驗(yàn)證控制下是完美的,但作為phper我們不能只有js驗(yàn)證而拋棄再一次安全驗(yàn)證。
(4) 缺少對(duì)表單某些屬性比如select、checkbox、radio、button等的驗(yàn)證,這些屬性在web頁(yè)面上開(kāi)發(fā)者已經(jīng)設(shè)置定其值和值域(白名單值),這些屬性值在js驗(yàn)證方面一般不會(huì)驗(yàn)證,因?yàn)楹戏ㄓ脩?hù)只有選擇權(quán)沒(méi)修改權(quán),然后phper就在后端接受數(shù)據(jù)處理驗(yàn)證數(shù)據(jù)的時(shí)候不會(huì)驗(yàn)證這些數(shù)據(jù),這是一個(gè)慣性思維,安全問(wèn)題也就有了,小人一個(gè)偽表單。
(5) 表單相應(yīng)元素name和數(shù)據(jù)表的字段名一致,如用戶(hù)表用戶(hù)名的字段是user_name,然后表單中的用戶(hù)名輸入框也是user_name,這和暴庫(kù)沒(méi)什么區(qū)別。
(6) 過(guò)濾危險(xiǎn)字符方面如防注入下面會(huì)獨(dú)立講解。
3、防注入
3.1簡(jiǎn)單判斷是否有注入漏洞以及原理。
網(wǎng)址:http://www.dbjr.com.cn/benwin.php?id=1 運(yùn)行正常,sql語(yǔ)句如:select * from phpben where id = 1
(1) 網(wǎng)址:http://www.dbjr.com.cn/benwin.php?id=1' sql語(yǔ)句如:select * from phpben where id = 1' 然后運(yùn)行異常 這能說(shuō)明benwin.php文件沒(méi)有對(duì)id的值進(jìn)行“'” 過(guò)濾和intval()整形轉(zhuǎn)換,當(dāng)然想知道有沒(méi)有對(duì)其他字符如“%”,“/*”等都可以用類(lèi)似的方法窮舉測(cè)試(很多測(cè)試軟件使用)
(2)網(wǎng)址:http://www.dbjr.com.cn/benwin.php?id=1 and 1=1 則sql語(yǔ)句可能是 select * from phpben where id = 1 and 1=1,運(yùn)行正常且結(jié)果和http://www.dbjr.com.cn/benwin.php?id=1結(jié)果一樣,則說(shuō)明benwin.php可能沒(méi)有對(duì)空格“ ”、和“and”過(guò)濾(這里是可能,所以要看下一點(diǎn))
(3)網(wǎng)址:http://www.dbjr.com.cn/benwin.php?id=1 and 1=2則sql語(yǔ)句可能是 select * from phpben where id = 1 and 1=2 如果運(yùn)行結(jié)果異常說(shuō)明sql語(yǔ)句中“and 1=2”起作用,所以能3個(gè)條件都滿足都則很確定的benwin.php存在注入漏洞。
ps:這里用get方法驗(yàn)證,post也可以,只要把值按上面的輸入,可以一一驗(yàn)證。
3.2常見(jiàn)的mysql注入語(yǔ)句。
(1)不用用戶(hù)名和密碼
//正常語(yǔ)句
$sql ="select * from phpben where user_name='admin' and pwd ='123'";
//在用戶(hù)名框輸入'or'='or'或 'or 1='1 然后sql如下
$sql ="select * from phpben where user_name=' 'or'='or'' and pwd ='' ";
$sql ="select * from phpben where user_name=' 'or 1='1' and pwd ='' ";
這樣不用輸入密碼。話說(shuō)筆者見(jiàn)到登錄框都有嘗試的沖動(dòng)。
(2)在不輸入密碼的情況下,利用某用戶(hù)。
//正常語(yǔ)句
$sql ="select * from phpben where user_name='$username' and pwd ='$pwd'";
//利用的用戶(hù)名是benwin 則用戶(hù)名框輸入benwin'# 密碼有無(wú)都可,則$sql變成
$sql ="select * from phpben where user_name=' benwin'#' and pwd ='$pwd'";
這是因?yàn)閙ysql中其中的一個(gè)注悉是“#”,上面語(yǔ)句中#已經(jīng)把后面的內(nèi)容給注悉掉,所以密碼可以不輸入或任意輸入。網(wǎng)上有些人介紹說(shuō)用“/*”來(lái)注悉,筆者想提的是只有開(kāi)始注悉沒(méi)結(jié)束注悉“*/”時(shí),mysql會(huì)報(bào)錯(cuò),也不是說(shuō)“/**/”不能注悉,而是這里很難添加上“*/”來(lái)結(jié)束注悉,還有“– ”也是可以注悉mysql 但要注意“–”后至少有一個(gè)空格也就是“– ”,當(dāng)然防注入代碼要把三種都考慮進(jìn)來(lái),值得一提的是很多防注入代碼中沒(méi)把“– ”考慮進(jìn)防注入范圍。
(3)猜解某用戶(hù)密碼
//正常語(yǔ)句
$sql ="select * from phpben.com where user_name='$username' and pwd ='$pwd'";
//在密碼輸入框中輸入“benwin' and left(pwd,1)='p'#”,則$sql是
$sql ="select * from phpben.com where user_name=' benwin' and left(pwd,1)='p'#' and pwd ='$pwd'";
如果運(yùn)行正常則密碼的密碼第一個(gè)字符是p,同理猜解剩下字符。
(4)插入數(shù)據(jù)時(shí)提權(quán)
//正常語(yǔ)句,等級(jí)為1
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',1) ";
//通過(guò)修改密碼字符串把語(yǔ)句變成
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',5)#',1) ";
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',5)-- ',1) ";這樣就把一個(gè)權(quán)限為1的用戶(hù)提權(quán)到等級(jí)5
(5)更新提權(quán)和插入提權(quán)同理
//正常語(yǔ)句
$sql = "update phpben set `user_name` ='benwin', level=1";
//通過(guò)輸入用戶(hù)名值最終得到的$sql
$sql = "update phpben set `user_name` ='benwin',level=5#', level=1";
$sql = "update phpben set `user_name` ='benwin',level=5-- ', level=1";
(6)惡意更新和刪除
//正常語(yǔ)句
$sql = "update phpben set `user_name` = ‘benwin' where id =1";
//注入后,惡意代碼是“1 or id>0”
$sql = "update phpben set `user_name` = ‘benwin' where id =1 or id>0";
//正常語(yǔ)句
$sql = "update phpben set `user_name` ='benwin' where id=1";
//注入后
$sql = "update phpben set `user_name` ='benwin' where id>0#' where id=1";
$sql = "update phpben set `user_name` ='benwin' where id>0-- ' where id=1";
(7)union、join等
//正常語(yǔ)句
$sql ="select * from phpben1 where `user_name`='benwin' ";
//注入后
$sql ="select * from phpben1 where`user_name`='benwin' uninon select * from phpben2#' ";
$sql ="select * from phpben1 where`user_name`='benwin' left join……#' ";
(8)通配符號(hào)%、_
//正常語(yǔ)句
$sql ="select * from phpben where `user_name`='benwin' ";
//注入通配符號(hào)%匹配多個(gè)字符,而一個(gè)_匹配一個(gè)字符,如__則匹配兩個(gè)字符
$sql ="select * from phpben where `user_name` like '%b' ";
$sql ="select * from phpben where `user_name` like '_b_' ";
這樣只要有一個(gè)用戶(hù)名字是b開(kāi)頭的都能正常運(yùn)行,“ _b_”是匹配三個(gè)字符,且這三個(gè)字符中間一個(gè)字符時(shí)b。這也是為什么有關(guān)addslashes()函數(shù)介紹時(shí)提示注意沒(méi)有轉(zhuǎn)義%和_(其實(shí)這個(gè)是很多phper不知問(wèn)什么要過(guò)濾%和_下劃線,只是一味的跟著網(wǎng)上代碼走)
(9)還有很多猜測(cè)表信息的注入sql
//正常語(yǔ)句
$sql ="select * from phpben1 where`user_name`='benwin'";
//猜表名,運(yùn)行正常則說(shuō)明存在phpben2表
$sql ="select * from phpben1 where`user_name`='benwin' and (select count(*) from phpben2 )>0#' ";
//猜表字段,運(yùn)行正常則說(shuō)明phpben2表中有字段colum1
$sql ="select * from phpben1 where`user_name`='benwin' and (select count(colum1) from phpben2 )>0#'";
//猜字段值
$sql ="select * from phpben1 where`user_name`='benwin' and left(pwd,1)='p'#''";
當(dāng)然還有很多,筆者也沒(méi)研究到專(zhuān)業(yè)人士那種水平,這里提出這些都是比較常見(jiàn)的,也是phper應(yīng)該知道并掌握的,而不是一味的在網(wǎng)上復(fù)制粘貼一些防注入代碼,知然而不解其然。
下面一些防注入方法回看可能更容易理解。
3.3防注入的一些方法
3.3.1 php可用于防注入的一些函數(shù)和注意事項(xiàng)。
(1)addslashes 和stripslashes。
Addslashes給這些 “'”、“””、“\”,“NULL” 添加斜桿“\'”、“\””、“\\”,“\NULL”, stripslashes則相反,這里要注意的是php.ini是否開(kāi)啟了magic_quotes_gpc=ON,開(kāi)啟若使用addslashes會(huì)出現(xiàn)重復(fù)。所以使用的時(shí)候要先get_magic_quotes_gpc()檢查
一般代碼類(lèi)似:
if(!get_magic_quotes_gpc())
{
$abc = addslashes($abc);
}
其實(shí)這個(gè)稍微學(xué)習(xí)php一下的人都知道了,只不過(guò)筆者想系統(tǒng)點(diǎn)介紹(前面都說(shuō)不是專(zhuān)家級(jí)文章),所以也順便寫(xiě)上了。addslashes
(2)mysql_escape_string()和mysql_ real _escape_string()
mysql_real_escape_string 必須在(PHP 4 >= 4.3.0, PHP 5)的情況下才能使用。否則只能用 mysql_escape_string
if (PHP_VERSION >= '4.3')
{
$string = mysql_real_escape_string($string);
}else
{
$string = mysql_escape_string($string );
}
mysql_escape_string()和mysql_ real _escape_string()卻別在于后者會(huì)判斷當(dāng)前數(shù)據(jù)庫(kù)連接字符集,換句話說(shuō)在沒(méi)有連接數(shù)據(jù)庫(kù)的前提下會(huì)出現(xiàn)類(lèi)似錯(cuò)誤:
Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: Access denied for user 'ODBC'@'localhost' (using password: NO) in E:\webphp\test.php on line 11
(3)字符代替函數(shù)和匹配函數(shù)
str_replace() 、perg_replace()這些函數(shù)之所以也在這里提是因?yàn)檫@些函數(shù)可以用于過(guò)濾或替代一些敏感、致命的字符。
3.3.2防注入字符優(yōu)先級(jí)。
防注入則要先知道有哪些注入字符或關(guān)鍵字,常見(jiàn)的mysql注入字符有字符界定符號(hào)如“'”、“””;邏輯關(guān)鍵字如“and”、“or”;mysql注悉字符如“#”,“– ”,“/**/”;mysql通配符“%”,“_”;mysql關(guān)鍵字“select|insert|update|delete|*|union|join|into|load_file|outfile”
(1)對(duì)于一些有規(guī)定格式的參數(shù)來(lái)說(shuō),防注入優(yōu)先級(jí)最高的是空格” ”。
如一些銀行卡號(hào),身份證號(hào),郵箱,電話號(hào)碼,,生日,郵政編碼等這些有自己規(guī)定的格式且格式規(guī)定不能有空格符號(hào)的參數(shù),在過(guò)濾的時(shí)候一般最先過(guò)濾掉空格(包括一些空格“變種”),因?yàn)槠渌址缍ǚ?hào),邏輯關(guān)鍵字,mysql注悉,注意下圖可以看出重要的是“'”,“ ”
ps:空格字符的變種有:“%20”,“\n”,“\r”,“\r\n”,“\n\r”,“chr(“32″)” 這也是為什么mysql_escape_string()和mysql_real_escape_string() 兩個(gè)函數(shù)轉(zhuǎn)義“\n”,“\r”。其實(shí)很多phper只知道轉(zhuǎn)義\n,\r而不知原因,在mysql解析\n,\r時(shí)把它們當(dāng)成空格處理,筆者測(cè)試驗(yàn)證過(guò),這里就不貼代碼了。
(2)“and”,“or”,“\”,“#”,“– ”
邏輯關(guān)鍵可以組合很多注入代碼;mysql注悉則把固有sql代碼后面的字符全部給注悉掉從而讓注入后的sql語(yǔ)句能正常運(yùn)行;“\”也是能組合很多注入字符\x00,\x1a。
ps:sql解析“#”,“– ”是大多數(shù)mysql防注入代碼沒(méi)有考慮到的,也是很多phper忽略。還有因?yàn)橐恍﹑hper給參數(shù)賦值的時(shí)候會(huì)有用“-”來(lái)隔開(kāi),所以筆者建議不要這樣寫(xiě)參數(shù),當(dāng)然也可以再過(guò)濾參數(shù)的時(shí)候“– ”(注意有空格的,沒(méi)空格不解析為注悉)當(dāng)一個(gè)整體過(guò)濾而不是過(guò)濾“-” ,這樣就避免過(guò)多過(guò)濾參數(shù)。
(3)“null”,“%”,“_”
這幾個(gè)不能獨(dú)立,都不要在特定情況下,比如通配字符“%,_”都要在mysql like子句的前提下。所以“%”,“_”的過(guò)濾一般在搜索相關(guān)才過(guò)濾,不能把它們納入通常過(guò)濾隊(duì)列,因?yàn)橛行┤玎]箱就可以有”_”字符
(4)關(guān)鍵字“select|insert|update|delete|*|union|join|into|load_file|outfile”
也許你會(huì)問(wèn)怎么這些重要關(guān)鍵字卻優(yōu)先級(jí)這么低。筆者想說(shuō)的是因?yàn)檫@些關(guān)鍵字在沒(méi)有“'”,“””,“ ”,“and”,“or”等情況下購(gòu)不成傷害。換句話說(shuō)這些關(guān)鍵字不夠“獨(dú)立”,“依賴(lài)性”特別大。當(dāng)然優(yōu)先級(jí)低,不代表不要過(guò)濾。
3.3.3防注入代碼。
(1)參數(shù)是數(shù)字直接用intval()函數(shù)
注意:現(xiàn)在很多網(wǎng)上流行的防注入代碼都只是只是用addslashes()、mysql_escape_string()、mysql_real_escape_string()或三者任意組合過(guò)濾,但phper以為過(guò)濾了,一不小心一樣有漏洞,那就是在參數(shù)為數(shù)字的時(shí)候:
$sql =" select * from phpben.com where id =$id";
$sql =" select * from phpben.com where id =1 or 1=1";
對(duì)比容易發(fā)現(xiàn),post過(guò)來(lái)的數(shù)據(jù)通過(guò)addslashes過(guò)濾后的確很多注入已經(jīng)不起作用,但是$id并沒(méi)有intval,導(dǎo)致漏洞的存在,這是個(gè)小細(xì)節(jié),不小心則導(dǎo)致漏洞。
(2)對(duì)于非文本參數(shù)的過(guò)濾
文本參數(shù)是指標(biāo)題、留言、內(nèi)容等可能有“'”,“'”等內(nèi)容,過(guò)濾時(shí)不可能全部轉(zhuǎn)義或代替。
但非文本數(shù)據(jù)可以。
function _str_replace($str )
{
$str = str_replace(" ","",$str);
$str = str_replace("\n","",$str);
$str = str_replace("\r","",$str);
$str = str_replace("'","",$str);
$str = str_replace('"',"",$str);
$str = str_replace("or","",$str);
$str = str_replace("and","",$str);
$str = str_replace("#","",$str);
$str = str_replace("\\","",$str);
$str = str_replace("-- ","",$str);
$str = str_replace("null","",$str);
$str = str_replace("%","",$str);
//$str = str_replace("_","",$str);
$str = str_replace(">","",$str);
$str = str_replace("<","",$str);
$str = str_replace("=","",$str);
$str = str_replace("char","",$str);
$str = str_replace("declare","",$str);
$str = str_replace("select","",$str);
$str = str_replace("create","",$str);
$str = str_replace("delete","",$str);
$str = str_replace("insert","",$str);
$str = str_replace("execute","",$str);
$str = str_replace("update","",$str);
$str = str_replace("count","",$str);
return $str;
}
ps:還有一些從列表頁(yè)操作過(guò)來(lái)的一般href是”phpben.php?action=delete&id=1”,這時(shí)候就注意啦,_str_replace($_GET['action'])會(huì)把參數(shù)過(guò)濾掉,筆者一般不用敏感關(guān)鍵作為參數(shù),比如delete會(huì)寫(xiě)成del,update寫(xiě)成edite,只要不影響可讀性即可;
還有上面代碼過(guò)濾下劃線的筆者注悉掉了,因?yàn)橛行﹨?shù)可以使用下劃線,自己權(quán)衡怎么過(guò)濾;
有些代碼把關(guān)鍵字當(dāng)重點(diǎn)過(guò)濾對(duì)象,其實(shí)關(guān)鍵字的str_replace很容易“蒙過(guò)關(guān)”,str_replace(“ininsertsert”)過(guò)濾后的字符還是insert,所以關(guān)鍵的是其他字符而不是mysql關(guān)鍵字。
(3)文本數(shù)據(jù)防注入代碼。
文本參數(shù)是指標(biāo)題、留言、內(nèi)容等這些數(shù)據(jù)不可能也用str_replace()過(guò)濾掉,這樣就導(dǎo)致數(shù)據(jù)的完整性,這是很不可取的。
代碼:
function no_inject($str)
{
if(is_array($str))
{
foreach($str as $key =>$val)
{
$str[$key]=no_inject($val);
}
}else
{
$str = str_replace(" "," ",$str);
$str = str_replace("\\","\",$str);
$str = str_replace("'","'",$str);
$str = str_replace('"',""",$str);
$str = str_replace("or","or",$str);
$str = str_replace("and","and",$str);
$str = str_replace("#","#",$str);
$str = str_replace("-- ","-- ",$str);
$str = str_replace("null","null",$str);
$str = str_replace("%","%",$str);
//$str = str_replace("_","",$str);
$str = str_replace(">",">",$str);
$str = str_replace("<","<",$str);
$str = str_replace("=","=",$str);
$str = str_replace("char","char",$str);
$str = str_replace("declare","declare",$str);
$str = str_replace("select","select",$str);
$str = str_replace("create","create",$str);
$str = str_replace("delete","delete",$str);
$str = str_replace("insert","insert",$str);
$str = str_replace("execute","execute",$str);
$str = str_replace("update","update",$str);
$str = str_replace("count","count",$str);
}
return $str;
}
(4)當(dāng)然還有其他與addslashes、mysql_escape_string結(jié)合的代碼。
防注入的代碼其實(shí)來(lái)來(lái)去去都是那些組合,然后根據(jù)自己程序代碼變通,筆者這些代碼也是沒(méi)考慮全的,不如cookes、session、request都沒(méi)全過(guò)濾。重要是知道其中原理,為什么過(guò)濾這些字符,字符有什么危害。
4、防止xss攻擊
XSS:cross site script 跨站腳本,為什么不叫css,為了不和div+css混淆。
4.1Xss攻擊過(guò)程:
(1)發(fā)現(xiàn)A站有xss漏洞。
(2)注入xss漏洞代碼??梢詊s代碼,木馬,腳本文件等等,這里假如A站的benwin.php這個(gè)文件有漏洞。
(3)通過(guò)一些方法欺騙A站相關(guān)人員運(yùn)行benwin.php,其中利用相關(guān)人員一些會(huì)員信息如cookies,權(quán)限等。
相關(guān)人員:
管理員(如貼吧版主),管理員一般有一定權(quán)限。目的是借用管理員的權(quán)限或進(jìn)行提權(quán),添或加管理員,或添加后門(mén),或上傳木馬,或進(jìn)一步滲透等相關(guān)操作。
A站會(huì)員:會(huì)員運(yùn)行A站的benwin.php。目的一般是偷取會(huì)員在A站的信息資料。
方法:
1) 在A站發(fā)誘騙相關(guān)人到benwin.php的信息,比如網(wǎng)址,這種是本地誘騙
2) 在其他網(wǎng)站發(fā)誘騙信息或者發(fā)郵件等等信息。
一般通過(guò)偽裝網(wǎng)址騙取A站相關(guān)人員點(diǎn)擊進(jìn)benwin.php
(4)第三步一般已經(jīng)是一次xss攻擊,如果要更進(jìn)一步攻擊,那不斷重復(fù)執(zhí)行(2)、(3)步以達(dá)到目的。
簡(jiǎn)單例說(shuō)xss攻擊
代碼:benwin.php文件
<html>
<head>
<title>簡(jiǎn)單xss攻擊例子</title></head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<dody>
<form action="phpben.com?user_name=<?php echo $user_name; ?>">
<input type="submit" value="提交" >
</form>
</body>
</html>
當(dāng)用戶(hù)名$user_name的值是“benwin” onSubmit=”alert(‘這是xss攻擊的例子');” class= “”(這里)
<form action="phpben.com?user_name=benwin" onSubmit="alert('這是xss攻擊的例子');" class= "" >
<input type="submit" value="提交" >
</form>
當(dāng)提交表單的時(shí)候就會(huì)彈出提示框。
(1) 很明顯$user_name在保存進(jìn)數(shù)據(jù)庫(kù)的時(shí)候沒(méi)有過(guò)濾xss字符(和防注入很像,這里舉例說(shuō)明)==>發(fā)現(xiàn)漏洞
(2) 構(gòu)造xss代碼:benwin” onSubmit=”alert(‘這是xss攻擊的例子');” class= “” 傳入數(shù)據(jù)庫(kù)
(3) 騙相關(guān)人員進(jìn)來(lái)點(diǎn)擊“提交”按鈕
4.2常見(jiàn)xss攻擊地方
(1)Js地方
<script language="javascript">
var testname =" <?php echo $testname;?>";
</script>
$testname的值只要符合js閉合關(guān)系:“”;alert(“test xss “);”(以下同理)
(2)form表單里面
<input type="text" name="##" value="<?php echo $val; ?>" />
(3)a標(biāo)簽
<a href="benwin.php?id= <?php echo $id; ?>">a標(biāo)簽可以隱藏xss攻擊</a>
(4)用得很多的img標(biāo)簽
<img src="<?php echo $picPath; ?>" />
甚至一些文本中插入整個(gè)img標(biāo)簽并且用width、 height、css等隱藏的很隱蔽
(5)地址欄
總之,有輸出數(shù)據(jù)的地方,更準(zhǔn)確的說(shuō)是有輸出用戶(hù)提交的數(shù)據(jù)的地方,都有可能是XSS攻擊的地方。
4.3防XSS方法
防xss方法其實(shí)和防注入很相似,都是一些過(guò)濾、代替、實(shí)體化等方法
(1)過(guò)濾或移除特殊的Html標(biāo)簽。
例如:< 、>、<,、> '、”、<script>、 <iframe> 、<,、>、"
(2)過(guò)濾觸發(fā)JavaScript 事件的標(biāo)簽。例如 onload、onclick、onfocus、onblur、onmouseover等等。
(3)php一些相關(guān)函數(shù),strip_tags()、htmlspecialchars()、htmlentities()等函數(shù)可以起作用
5、CSRF
CSRF跨站請(qǐng)求偽造cross site request forgery。
5.1簡(jiǎn)單說(shuō)明CSRF原理
(1)A登錄Site1(如現(xiàn)在網(wǎng)民常上的淘寶、微博、QQ等),產(chǎn)生一些信息,session、cookies等等,且一直保持沒(méi)退出。
(2)A再登錄Site2(如一些成人網(wǎng)等,至于怎么跑到Site2,多數(shù)是Site通過(guò)些手段,郵件欺騙等),打開(kāi)site2的瀏覽器和打開(kāi)site1的一樣,否則無(wú)效
(3)Site2站中偽造了Site1的http請(qǐng)求(如修改密碼,買(mǎi)東西,轉(zhuǎn)賬等),Site1的服務(wù)器誤以為A在site1的正常操作(因?yàn)橥瑸g覽器且A還沒(méi)登出),然后就運(yùn)行了請(qǐng)求,那么csrf已成功操作。
csrf和xss很相似。xss也能偽造請(qǐng)求,csrf也能制造腳本。
偽造的請(qǐng)求可以很多方面,發(fā)郵件、改密碼、返回用戶(hù)信息、交易等等,所以相對(duì)與xss攻擊來(lái)說(shuō)csrf危害更嚴(yán)重。
5.2防范方法。
對(duì)于phper
(1)嚴(yán)密操控執(zhí)行入口
執(zhí)行一些敏感操作比如改密碼這些操作前判斷請(qǐng)求來(lái)源,只有本站服務(wù)器發(fā)的請(qǐng)求才可以執(zhí)行。判斷方法可以判斷ip來(lái)源。非本站服務(wù)器ip不會(huì)執(zhí)行。
(2)本站有外鏈的話做些必要操作
一般site2的hacker會(huì)在site1(比如論壇里)里發(fā)欺騙連接,因?yàn)樵趕ite1誘騙的相關(guān)人員一般都登錄site1了,滿足csrf氣體條件之一。
如當(dāng)你點(diǎn)擊QQ郵件里面的長(zhǎng)外鏈時(shí)候,回跳轉(zhuǎn)到一個(gè)頁(yè)面提示“有風(fēng)險(xiǎn)”之類(lèi),這樣不僅可以減低跳出率,一些不懂的人看到這樣的提示,若不是非必要而是處于好奇點(diǎn)擊的連接一般不會(huì)繼續(xù)點(diǎn)擊訪問(wèn);還有是QQ郵件正文里的圖片在加載內(nèi)容時(shí)是不加載圖片的,要點(diǎn)擊“顯示圖片”按鈕才顯示圖片,這里一個(gè)原因之一就是避免攻擊。
當(dāng)然對(duì)于用戶(hù)體驗(yàn)來(lái)說(shuō)這是不可取的,可以?xún)?yōu)化的是判斷到一些網(wǎng)址(如QQ本身網(wǎng)址)是安全直接可以顯示(不用提示),而可疑的才提示或禁止。
(3)防止csrf也可以用防xss的方法。
6、防盜鏈
盜鏈問(wèn)題增加服務(wù)器的負(fù)擔(dān)。盜鏈就是盜鏈網(wǎng)站盜取被盜鏈網(wǎng)站資源來(lái)實(shí)現(xiàn)一些功能。盜鏈方面主要是圖片、視頻、以及其他資源下載文件。
方法:判斷ip,只有本站服務(wù)器才能使用站點(diǎn)資源,否則不能使用。
代碼:
(1)在Apache htaccess添加
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !phpben.com [NC]
RewriteCond %{HTTP_REFERER} !google.com [NC]
RewriteCond %{HTTP_REFERER} !baidu.com [NC]
RewriteCond %{HTTP_REFERER} !zhuaxia.com [NC]
RewriteRule .(jpg|gif|png|bmp|swf|jpeg) /image/replace.gif [R,NC,L]
RewriteRule ^(.*)$ http:\/\/phpben.com\/image\/$1 [L]
這樣,凡是不是phpben.com google.com baidu.com zhuaxia.com 域名請(qǐng)求的都返回replace.gif代替返回
7、防CC攻擊
CC攻擊:是利用不斷對(duì)網(wǎng)站發(fā)送連接請(qǐng)求致使形成拒絕服務(wù)的目的。
詳細(xì)百度百科:http://baike.baidu.com/view/662394.htm
代碼:
session_start();
$ll_nowtime = $timestamp ;
if (session_is_registered('ll_lasttime')){
$ll_lasttime = $_SESSION['ll_lasttime'];
$ll_times = $_SESSION['ll_times'] + 1;
$_SESSION['ll_times'] = $ll_times;
}else{
$ll_lasttime = $ll_nowtime;
$ll_times = 1;
$_SESSION['ll_times'] = $ll_times;
$_SESSION['ll_lasttime'] = $ll_lasttime;
}
if (($ll_nowtime - $ll_lasttime)<3){
if ($ll_times>=5){
header(sprintf("Location: %s",'http://127.0.0.1'));
exit;
}
}else{
$ll_times = 0;
$_SESSION['ll_lasttime'] = $ll_nowtime;
$_SESSION['ll_times'] = $ll_times;
}
相關(guān)文章
php自定義函數(shù)實(shí)現(xiàn)統(tǒng)計(jì)中文字符串長(zhǎng)度的方法小結(jié)
這篇文章主要介紹了php自定義函數(shù)實(shí)現(xiàn)統(tǒng)計(jì)中文字符串長(zhǎng)度的方法,結(jié)合實(shí)例形式總結(jié)分析了php針對(duì)中文的判定、編碼與運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-04-04
php 頁(yè)面執(zhí)行時(shí)間計(jì)算代碼
我們?cè)陂_(kāi)發(fā)網(wǎng)頁(yè)的時(shí)候,往往會(huì)測(cè)試一下自己寫(xiě)的網(wǎng)頁(yè)的執(zhí)行時(shí)間是多少,例如:有時(shí)網(wǎng)頁(yè)打開(kāi)很慢,但是不知道是卡在哪了,這時(shí)我們就可以使用以下的方法來(lái)判斷頁(yè)面的執(zhí)行時(shí)間是多少,準(zhǔn)確的找到問(wèn)題所在點(diǎn),精確到毫秒。2008-12-12
PHP+Apache實(shí)現(xiàn)二級(jí)域名之間共享cookie的方法
這篇文章主要介紹了PHP+Apache實(shí)現(xiàn)二級(jí)域名之間共享cookie的方法,涉及Apache的配置、hosts修改及php cookie操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-07-07
分享下php5類(lèi)中三種數(shù)據(jù)類(lèi)型的區(qū)別
這篇文章主要介紹了php5類(lèi)中三種數(shù)據(jù)類(lèi)型的區(qū)別,需要的朋友可以參考下2015-01-01
php 表單提交大量數(shù)據(jù)發(fā)生丟失的解決方法
這篇文章主要介紹了php表單提交大量數(shù)據(jù)、上千個(gè)文本框時(shí)發(fā)生數(shù)據(jù)丟失、數(shù)據(jù)不完整等問(wèn)題的解決方法,需要的朋友可以參考下2014-03-03
php select,radio和checkbox默認(rèn)選擇的實(shí)現(xiàn)方法
radio和checkbox默認(rèn)選擇的實(shí)現(xiàn)方法,大家參考下原理就知道了,不論asp,asp.net,jsp都是這個(gè)原理。2010-05-05

