淺談php web安全
轉載自:http://www.phpben.com/tb.php?sc=3b1ce8&id=79
前言:
首先,筆記不是web安全的專家,所以這不是web安全方面專家級文章,而是學習筆記、細心總結文章,裡面有些是我們phper不易發現或者說不重視的東西。所以筆者寫下來方便以後查閱。在大公司肯定有專門的web安全測試員,安全方面不是phper考慮的範圍。但是作為一個phper對於安全知識是:“知道有這麼一回事,程式設計時自然有所注意”。有什麼不妥、錯誤的請聯絡:[email protected]/[email protected]
概要:
1、php一些安全配置
(1)關閉php提示錯誤功能
(2)關閉一些“壞功能”
(3)嚴格配置檔案許可權。
2、嚴格的資料驗證,你的使用者不全是“好”人
2.1為了確保程式的安全性,健壯性,資料驗證應該包括內容。
2.2程式設計師容易漏掉point或者說需要注意的事項
3、防注入
3.1簡單判斷是否有注入漏洞以及原理
3.2常見的mysql注入語句
(1)不用使用者名稱和密碼
(2)在不輸入密碼的情況下,利用某使用者
(3)猜解某使用者密碼
(4)插入資料時提權
(5)更新提權和插入提權同理
(6)惡意更新和刪除
(7)union、join等
(8)萬用字元號%、_
(9)還有很多猜測表資訊的注入sql
33防注入的一些方法
2.3.1 php可用於防注入的一些函式和注意事項。
2.3.2防注入字元優先順序。
2.3.3防注入程式碼
(1)引數是數字直接用intval()函式
(2)對於非文字引數的過濾
(3)文字資料防注入程式碼。
(4)當然還有其他與addslashes、mysql_escape_string結合的程式碼。
4、防止xss攻擊
4.1Xss攻擊過程
4.2常見xss攻擊地方
4.3防XSS方法
5、CSRF
5.1簡單說明CSRF原理
5.2防範方法
6、防盜鏈
7、防拒CC攻擊
---------------------------------------------------------------------
1、php一些安全配置
(1)關閉php提示錯誤功能
在php.ini 中把display_errors改成
display_errors = OFF
或在php檔案前加入
error_reporting(0)
1)使用error_reporting(0);失敗的例子:
A檔案程式碼:
<?
error_reporting(0);
echo 555
echo 444;
?>
錯誤:
Parse error: parse error, expecting `','' or `';'' in E:\webphp\2.php on line 4
2)使用error_reporting(0);成功的例子:
a檔案程式碼:
<?php
error_reporting(0);
include("b.php");
?>
b檔案程式碼:
<?php
echo 555
echo 444;
?>
這是很多phper說用error_reporting(0)不起作用。第一個例子A.php裡面有致命錯誤,導致不能執行,不能執行伺服器則不知有這個功能,所以一樣報錯。
第二個例子中a.php成功執行,那麼伺服器知道有抑制錯誤功能,所以就算b.php有錯誤也抑制了。
ps:抑制不了mysql錯誤。
(2)關閉一些“壞功能”
1)關閉magic quotes功能
在php.ini 把magic_quotes_gpc = OFF
避免和addslashes等重複轉義
2)關閉register_globals = Off
在php.ini 把register_globals = OFF
在register_globals = ON的情況下
位址列目:http:www.phpben.com?bloger=benwin
<?php
//$bloger = $_GET['bloger'] //因為register_globals = ON 所以這步不用了直接可以用$bloger
echo $bloger;
?>
這種情況下會導致一些未初始化的變數很容易被修改,這也許是致命的。所以把register_globals = OFF關掉
(3)嚴格配置檔案許可權。
為相應資料夾分配許可權,比如包含上傳圖片的檔案不能有執行許可權,只能讀取
2、嚴格的資料驗證,你的使用者不全是“好”人。
記得筆者和一個朋友在討論資料驗證的時候,他說了一句話:你不要把你使用者個個都想得那麼壞!但筆者想說的這個問題不該出現在我們開發情景中,我們要做的是嚴格驗證控制資料流,哪怕10000萬用戶中有一個是壞使用者也足以致命,再說好的使用者也有時在資料input框無意輸入中文的時,他已經不經意變“壞”了。
2.1為了確保程式的安全性,健壯性,資料驗證應該包括
(1) 關鍵資料是否存在。如刪除資料id是否存在
(2) 資料型別是否正確。如刪除資料id是否是整數
(3) 資料長度。如欄位是char(10)型別則要strlen判斷資料長度
(4) 資料是否有危險字元
資料驗證有些人主張是把功能完成後再慢慢去寫安全驗證,也有些是邊開發邊寫驗證。筆者偏向後者,這兩種筆者都試過,然後發現後者寫的驗證相對健壯些,主要原因是剛開發時想到的安全問題比較齊全,等開發完功能再寫時有兩個問題,一個phper急於完成指標草草完事,二是確實漏掉某些point。
2.2程式設計師容易漏掉point或者說需要注意的事項:
(1) 進庫資料一定要安全驗證,筆者在廣州某家公司參與一個公司內部系統開發的時候,見過直接把$_POST資料傳給類函式classFunctionName($_POST),理由竟然是公司內部使用的,不用那麼嚴格。暫且不說邏輯操作與資料操控耦合高低問題,連判斷都沒判斷的操作是致命的。安全驗證必須,沒任何理由推脫。
(2) 資料長度問題,如資料庫建表字段char(25),大多phper考慮到是否為空、資料型別是否正確,卻忽略字元長度,忽略還好更多是懶於再去判斷長度。(這個更多出現在新手當中,筆者曾經也有這樣的思想)
(3) 以為前端用js判斷驗證過了,後臺不需要判斷驗證。這也是致命,要知道偽造一個表單就幾分鐘的事,js判斷只是為了減少使用者提交次數從而提高使用者體驗、減少http請求減少伺服器壓力,在安全情況下不能防“小人”,當然如果合法使用者在js驗證控制下是完美的,但作為phper我們不能只有js驗證而拋棄再一次安全驗證。
(4) 缺少對錶單某些屬性比如select、checkbox、radio、button等的驗證,這些屬性在web頁面上開發者已經設定定其值和值域(白名單值),這些屬性值在js驗證方面一般不會驗證,因為合法使用者只有選擇權沒修改權,然後phper就在後端接受資料處理驗證資料的時候不會驗證這些資料,這是一個慣性思維,安全問題也就有了,小人一個偽表單足矣致命。
(5) 表單相應元素name和資料表的欄位名一致,如使用者表使用者名稱的欄位是user_name,然後表單中的使用者名稱輸入框也是user_name ,這和暴庫沒什麼區別。
(6) 過濾危險字元方面如防注入下面會獨立講解。
3、防注入
3.1簡單判斷是否有注入漏洞以及原理。
網址:http:www.phpben.com/benwin.php?id=1 執行正常,sql語句如:select * from phpben where id = 1
(1) 網址:http:www.phpben.com/ benwin.php?id=1’ sql語句如:select * from phpben where id = 1’ 然後執行異常 這能說明benwin.php檔案沒有對id的值進行“’” 過濾和intval()整形轉換,當然想知道有沒有對其他字元如“%”,“/*”等都可以用類似的方法窮舉測試(很多測試軟體使用)
(2)網址:http:www.phpben.com/ benwin.php?id=1 and 1=1 則sql語句可能是 select * from phpben where id = 1 and 1=1,執行正常且結果和http:www.phpben.com/benwin.php?id=1結果一樣,則說明benwin.php可能沒有對空格“ ”、和“and”過濾(這裡是可能,所以要看下一點)
(3)網址:http:www.phpben.com/ benwin.php?id=1 and 1=2則sql語句可能是 select * from phpben where id = 1 and 1=2 如果執行結果異常說明sql語句中“and 1=2”起作用,所以能3個條件都滿足都則很確定的benwin.php存在注入漏洞。
ps:這裡用get方法驗證,post也可以,只要把值按上面的輸入,可以一一驗證。
這說明
3.2常見的mysql注入語句。
(1)不用使用者名稱和密碼
這樣不用輸入密碼。話說筆者見到登入框都有嘗試的衝動。
//正常語句
$sql ="select * from phpben where user_name='admin' and pwd ='123'";
//在使用者名稱框輸入’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 ='' ";
(2)在不輸入密碼的情況下,利用某使用者。
//正常語句
$sql ="select * from phpben where user_name='$username' and pwd ='$pwd'";
//利用的使用者名稱是benwin 則使用者名稱框輸入benwin’# 密碼有無都可,則$sql變成
$sql ="select * from phpben where user_name=' benwin'#' and pwd ='$pwd'";
這是因為mysql中其中的一個注悉是“#”,上面語句中#已經把後面的內容給注悉掉,所以密碼可以不輸入或任意輸入。網上有些人介紹說用“/*”來注悉,筆者想提的是隻有開始注悉沒結束注悉“*/”時,mysql會報錯,也不是說“/**/”不能注悉,而是這裡很難新增上“*/”來結束注悉,還有“-- ”也是可以注悉mysql 但要注意“--”後至少有一個空格也就是“-- ”,當然防注入程式碼要把三種都考慮進來,值得一提的是很多防注入程式碼中沒把“-- ”考慮進防注入範圍。
(3)猜解某使用者密碼
//正常語句
$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'";
如果執行正常則密碼的密碼第一個字元是p,同理猜解剩下字元。
(4)插入資料時提權
//正常語句,等級為1
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',1) ";
//通過修改密碼字串把語句變成
$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) ";這樣就把一個許可權為1的使用者提權到等級5
(5)更新提權和插入提權同理
//正常語句
$sql = "update phpben set `user_name` ='benwin', level=1";
//通過輸入使用者名稱值最終得到的$sql
$sql = "update phpben set `user_name` ='benwin',level=5#', level=1";
$sql = "update phpben set `user_name` ='benwin',level=5-- ', level=1";
(6)惡意更新和刪除
//正常語句
$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";
//正常語句
$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等
//正常語句
$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)萬用字元號%、_
- //正常語句
- $sql ="select * from phpben where `user_name`=’benwin’ ";
- //注入萬用字元號%匹配多個字元,而一個_匹配一個字元,如__則匹配兩個字元
- $sql ="select * from phpben where `user_name` like ’%b’ ";
- $sql ="select * from phpben where `user_name` like ’_b_’ ";
這樣只要有一個使用者名稱字是b開頭的都能正常執行,“ _b_”是匹配三個字元,且這三個字元中間一個字元時b。這也是為什麼有關addslashes()函式介紹時提示注意沒有轉義%和_(其實這個是很多phper不知問什麼要過濾%和_下劃線,只是一味的跟著網上程式碼走)
(9)還有很多猜測表資訊的注入sql
//正常語句
$sql ="select * from phpben1 where`user_name`='benwin'";
//猜表名,執行正常則說明存在phpben2表
$sql ="select * from phpben1 where`user_name`='benwin' and (select count(*) from phpben2 )>0#' ";
//猜表字段,執行正常則說明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'#’'";
當然還有很多,筆者也沒研究到專業人士那種水平,這裡提出這些都是比較常見的,也是phper應該知道並掌握的,而不是一味的在網上覆制貼上一些防注入程式碼,知然而不解其然。
下面一些防注入方法回看可能更容易理解。
3.3防注入的一些方法
3.3.1 php可用於防注入的一些函式和注意事項。
(1)addslashes 和stripslashes。
Addslashes給這些 “’”、“””、“\”,“NULL” 新增斜杆“\’”、“\””、“\\”,“\NULL”, stripslashes則相反,這裡要注意的是php.ini是否開啟了magic_quotes_gpc=ON,開啟若使用addslashes會出現重複。所以使用的時候要先get_magic_quotes_gpc()檢查
一般程式碼類似:
if(!get_magic_quotes_gpc())
{
$abc = addslashes($abc);
}
其實這個稍微學習php一下的人都知道了,只不過筆者想系統點介紹(前面都說不是專家級文章),所以也順便寫上了。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()卻別在於後者會判斷當前資料庫連線字符集,換句話說在沒有連線資料庫的前提下會出現類似錯誤:
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)字元代替函式和匹配函式
str_replace() 、perg_replace()這些函式之所以也在這裡提是因為這些函式可以用於過濾或替代一些敏感、致命的字元。
3.3.2防注入字元優先順序。
防注入則要先知道有哪些注入字元或關鍵字,常見的mysql注入字元有字元界定符號如“'”、“"”;邏輯關鍵字如“and”、“or”;mysql注悉字元如“#”,“-- ”,“/**/”;mysql萬用字元“%”,“_”;mysql關鍵字“select|insert|update|delete|*|union|join|into|load_file|outfile”
(1)對於一些有規定格式的引數來說,防注入優先順序最高的是空格” ”。
如一些銀行卡號,身份證號,郵箱,電話號碼,,生日,郵政編碼等這些有自己規定的格式且格式規定不能有空格符號的引數,在過濾的時候一般最先過濾掉空格(包括一些空格“變種”),因為其他字元界定符號,邏輯關鍵字,mysql注悉,注意下圖可以看出重要的是“'”,“ ”
ps:空格字元的變種有:“%20”,“\n”,“\r”,“\r\n”,“\n\r”,“chr("32")” 這也是為什麼mysql_escape_string()和mysql_real_escape_string() 兩個函式轉義“\n”,“\r”。其實很多phper只知道轉義\n,\r而不知原因,在mysql解析\n,\r時把它們當成空格處理,筆者測試驗證過,這裡就不貼程式碼了。
(2)“and”,“or”,“\”,“#”,“-- ”
邏輯關鍵可以組合很多注入程式碼;mysql注悉則把固有sql程式碼後面的字元全部給注悉掉從而讓注入後的sql語句能正常執行;“\”也是能組合很多注入字元\x00,\x1a。
ps:sql解析“#”,“-- ”是大多數mysql防注入程式碼沒有考慮到的,也是很多phper忽略。還有因為一些phper給引數賦值的時候會有用“-”來隔開,所以筆者建議不要這樣寫引數,當然也可以再過濾引數的時候“-- ”(注意有空格的,沒空格不解析為注悉)當一個整體過濾而不是過濾“-” ,這樣就避免過多過濾引數。
(3)“null”,“%”,“_”
這幾個不能獨立,都不要在特定情況下,比如通配字元“%,_”都要在mysql like子句的前提下。所以“%”,“_”的過濾一般在搜尋相關才過濾,不能把它們納入通常過濾佇列,因為有些如郵箱就可以有”_”字元
(4)關鍵字“select|insert|update|delete|*|union|join|into|load_file|outfile”
也許你會問怎麼這些重要關鍵字卻優先順序這麼低。筆者想說的是因為這些關鍵字在沒有“'”,“"”,“ ”,“and”,“or”等情況下購不成傷害。換句話說這些關鍵字不夠“獨立”,“依賴性”特別大。當然優先順序低,不代表不要過濾。
3.3.3防注入程式碼。
(1)引數是數字直接用intval()函式
注意:現在很多網上流行的防注入程式碼都只是只是用addslashes()、mysql_escape_string()、mysql_real_escape_string()或三者任意組合過濾,但phper以為過濾了,一不小心一樣有漏洞,那就是在引數為數字的時候:
$id = addslashes($_POST['id']); //正確是$id = intval($_POST['id']);
$sql =" select * from phpben.com where id =$id";
$sql =" select * from phpben.com where id =1 or 1=1";
對比容易發現,post過來的資料通過addslashes過濾後的確很多注入已經不起作用,但是$id並沒有intval,導致漏洞的存在,這是個小細節,不小心則導致漏洞。
(2)對於非文字引數的過濾
文字引數是指標題、留言、內容等可能有“’”,“’”等內容,過濾時不可能全部轉義或代替。
但非文字資料可以。
- 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:
還有一些從列表頁操作過來的一般href是”phpben.php?action=delete&id=1”,這時候就注意啦,_str_replace($_GET['action'])會把引數過濾掉,筆者一般不用敏感關鍵作為引數,比如delete會寫成del,update寫成edite,只要不影響可讀性即可;
還有上面程式碼過濾下劃線的筆者注悉掉了,因為有些引數可以使用下劃線,自己權衡怎麼過濾;
有些程式碼把關鍵字當重點過濾物件,其實關鍵字的str_replace很容易“蒙過關”,str_replace(“ininsertsert”)過濾後的字元還是insert,所以關鍵的是其他字元而不是mysql關鍵字。
(3)文字資料防注入程式碼。
文字引數是指標題、留言、內容等這些資料不可能也用str_replace()過濾掉,這樣就導致資料的完整性,這是很不可取的。
程式碼:
- function no_inject($str)
- {
- if(is_array($str))
- {
- foreach($str as $key =>$val)
- {
- $str[$key]=no_inject($val);
- }
- }else
- {
- //把一些敏感關鍵字的第一個字母代替掉,如or 則用"or"代替
- $str = str_replace(" "," ",$str);
- $str = str_replace("\\","\",$str);
- $str = str_replace("'"," ' ",$str);
- $str = str_replace('"'," " ",$str);
- $str = str_replace("or"," o r",$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)當然還有其他與addslashes、mysql_escape_string結合的程式碼。
防注入的程式碼其實來來去去都是那些組合,然後根據自己程式程式碼變通,筆者這些程式碼也是沒考慮全的,不如cookes、session、request都沒全過濾。重要是知道其中原理,為什麼過濾這些字元,字元有什麼危害。當然還有一些筆者沒考慮也沒能力考慮到的方面比如還有哪些關鍵字之類,歡迎mailto:[email protected]/[email protected]
4、防止xss攻擊
XSS:cross site script 跨站指令碼,為什麼不叫css,為了不和div+css混淆。
4.1Xss攻擊過程:
(1)發現A站有xss漏洞。
(2)注入xss漏洞程式碼。可以js程式碼,木馬,指令碼檔案等等,這裡假如A站的benwin.php這個檔案有漏洞。
(3)通過一些方法欺騙A站相關人員執行benwin.php,其中利用相關人員一些會員資訊如cookies,許可權等。
相關人員:
管理員(如貼吧版主),管理員一般有一定許可權。目的是借用管理員的許可權或進行提權,添或加管理員,或新增後門,或上傳木馬,或進一步滲透等相關操作。
A站會員:會員執行A站的benwin.php。目的一般是偷取會員在A站的資訊資料。
方法:
1) 在A站發誘騙相關人到benwin.php的資訊,比如網址,這種是本地誘騙
2) 在其他網站發誘騙資訊或者發郵件等等資訊。
一般通過偽裝網址騙取A站相關人員點選進benwin.php
(4)第三步一般已經是一次xss攻擊,如果要更進一步攻擊,那不斷重複執行(2)、(3)步以達到目的。
簡單例說xss攻擊
程式碼:
benwin.php檔案
- <html>
- <head>
- <title>簡單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>
當用戶名$user_name的值是“benwin" onSubmit="alert('這是xss攻擊的例子');" class= "”(這裡)
- <form action="phpben.com?user_name=benwin" onSubmit="alert('這是xss攻擊的例子');" class= "" >
- <input type="submit" value="提交" >
- </form>
當提交表單的時候就會彈出提示框。
(1) 很明顯$user_name在儲存進資料庫的時候沒有過濾xss字元(和防注入很像,這裡舉例說明)==>發現漏洞
(2) 構造xss程式碼:benwin" onSubmit="alert('這是xss攻擊的例子');" class= "" 傳入資料庫
(3) 騙相關人員進來點選“提交”按鈕
4.2常見xss攻擊地方
(1)Js地方
- <script language="javascript">
- var testname =" <?php echo $testname;?>";
- </script>
$testname的值只要符合js閉合關係:“";alert("test xss ");”(以下同理)
(2)form表單裡面
- <input type="text" name="##" value="<?php echo $val; ?>" />
(3)a標籤
- <a href="benwin.php?id= <?php echo $id; ?>">a標籤可以隱藏xss攻擊</a>
(4)用得很多的img標籤
- <img src="<?php echo $picPath; ?>" />
甚至一些文字中插入整個img標籤並且用width、 height、css等隱藏的很隱蔽
(5)位址列目
總之,有輸出資料的地方,更準確的說是有輸出使用者提交的資料的地方,都有可能是XSS攻擊的地方。
4.3防XSS方法
防xss方法其實和防注入很相似,都是一些過濾、代替、實體化等方法
(1)過濾或移除特殊的Html標籤。
例如:< 、>、<,、> ’、”、<script>、 <iframe> 、<,、>、"
(2)過濾觸發JavaScript 事件的標籤。例如 onload、onclick、onfocus、onblur、onmouseover等等。
(3)php一些相關函式,strip_tags()、htmlspecialchars()、htmlentities()等函式可以起作用
5、CSRF
CSRF跨站請求偽造cross site request forgery。
5.1簡單說明CSRF原理
(1)A登入Site1(如現在網民常上的淘寶、微博、QQ等),產生一些資訊,session、cookies等等,且一直保持沒退出。
(2)A再登入Site2(如一些成人網等,至於怎麼跑到Site2,多數是Site通過些手段,郵件欺騙等),開啟site2的瀏覽器和開啟site1的一樣,否則無效
(3)Site2站中偽造了Site1的http請求(如修改密碼,買東西,轉賬等),Site1的伺服器誤以為A在site1的正常操作(因為同瀏覽器且A還沒登出),然後就運行了請求,那麼csrf已成功操作。
csrf和xss很相似。
筆者開始也一時混淆,一位熱心網友提醒下,修改csrf和xss的區別
xss:注重於修改、獲取頁面元素和值,而且可以執行任意html程式碼或javascript,能執行程式碼那肯定能偷取cookies等網站資訊
csrf:不能修改、獲取頁面元素和值,而且可以執行任意html程式碼或javascript,注重利用客戶已在安全網站(比如淘寶)登入且產生給非安全網站利用的cookies等資訊,然後使用者在非安全網站點選連線等一些觸發非安全網站向安全網站傳送請求。
偽造的請求可以很多方面,發郵件、改密碼、返回使用者資訊、交易等等,所以相對與xss攻擊來說csrf危害更嚴重。
5.2防範方法。
對於phper
(1)嚴密操控執行入口
執行一些敏感操作比如改密碼這些操作前判斷請求來源,只有本站伺服器發的請求才可以執行。判斷方法可以判斷ip來源。非本站伺服器ip不會執行。
(2)本站有外鏈的話做些必要操作
一般site2的hacker會在site1(比如論壇裡)裡發欺騙連線,因為在site1誘騙的相關人員一般都登入site1了,滿足csrf氣體條件之一。
如當你點選QQ郵件裡面的長外鏈時候,回跳轉到一個頁面提示“有風險”之類,這樣不僅可以減低跳出率,一些不懂的人看到這樣的提示,若不是非必要而是處於好奇點選的連線一般不會繼續點選訪問;還有是QQ郵件正文裡的圖片在載入內容時是不載入圖片的,要點選“顯示圖片”按鈕才顯示圖片,這裡一個原因之一就是避免攻擊。
當然對於使用者體驗來說這是不可取的,可以優化的是判斷到一些網址(如QQ本身網址)是安全直接可以顯示(不用提示),而可疑的才提示或禁止。
(3)防止csrf也可以用防xss的方法。
6、防盜鏈
盜鏈問題增加伺服器的負擔。盜鏈就是盜鏈網站盜取被盜鏈網站資源來實現一些功能。盜鏈方面主要是圖片、視訊、以及其他資源下載檔案。
方法:判斷ip,只有本站伺服器才能使用站點資源,否則不能使用。
程式碼:
(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 域名請求的都返回replace.gif代替返回
7、防CC攻擊
CC攻擊:是利用不斷對網站傳送連線請求致使形成拒絕服務的目的。
程式碼:
- 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;
- }