|
變量
所有漏洞都來源于變量,因此變量首先要做的就是定義初始化。用任何一個變量前一定要先定義,初始化它
雖然現在Discuz!X來說,GPC不會被全局覆蓋了,但是大家寫插件的過程中也不要忽視了
因為在服務器php.ini的配置中 global on 時
所有的GET POST 都會變成變量
$_GET['xxx'] 如果存在
就會變成 $xxx 而產生在程序里
因此,你自己要用的變量,一定要初始化
第一點,變量的初始化
無論你要怎么利用變量,一定要初始化
不管是Discuz!還是Discuz!X
由于PHP的歷史原因
你不能相信任何一個服務器
只因為php有個global on 的參數
他會讓GPC變量直接變成全局變量
因此,你自己的變量一定要初始化
第二點,認清變量的類型
整剛才說到,變量一定要初始化,那么初始化成什么類型
如果你要用于數組
初始化$a = array();
字串 $a ='';
數字 $a = 0
這樣子,這里說說數組,這里又存在一個php歷史問題,這歷史延續至今。
$s = '123456';
echo $s[2];
等于什么?
[]大家都知,這是數組的用法,但php太自由了 $s[3] 的數組用法,竟然可以用在字串里,這個在大家認為很自然。
但是,很多漏洞會從此誕生,這就是認清自己的變量類型的道理所在。
$s[1] 是數組的用法,可以用在字串中,但是我不推薦大家用,黑客會這么用在GET中更改你的變量類型。
舉例
echo $s[2];
簡單這一句,你認為這是輸出數組的一個項,還是字串?
大多數人會認為這明顯是輸出數組的一個項目,但是剛才也看到了,它輸出字串的一個字節也可以。
那,我們反過來思考,如果程序的某邏輯需要輸出字串的某字節,但是,如果你沒明確告知變量類型。那么有可能會讓這一個字節變成一個字串 xxx.php?s[2]=hello
初始化+認清自己的變量類型
特別是數組和字串,如果你要取字串的某一位,安全的方法,可能還是 substr($s, 2, 1)
切忌[]的用法,一定要$a = array() 不要讓他和字串類型的變量產生互用理中
第三點、不要相信任何一個即將入庫的變量
進很多SQL注入都是從變量開始,要仔細看每一個SQL語句中可能出現的變量,如,整數一定要intval;字串一定要addslashes處理,說到addslashes,說說Discuz!的特點,國外某些論壇是,所有變量都無需addslashes,addslashes只在SQL數據庫類中統一處理,但Discuz!不是,Discuz!會統一給GPC變量自動addslashes。
注意,是只給GPC變量加addslashes,其他的都沒加。所以,你要注意兩件事:
1. GPC變量你想用于顯示?
那么別忘記stripslashes 后在顯示,否則萬一遇到有帶有 ' 的,那就會多一個\,I'm 變成 I\'m
htmlspecial只處理<>這些,和單引號無關
2. 再次,剛才說過DZ只處理GPC。因此,GPC之外的所有變量一定要自己addslashes,特別是有些時候時,把A庫的東西讀出來后,直接復制到B庫的情況。有人說A庫的東西都入進去了,直接入B庫還不安全嗎?這可不一定,I'm 被A讀取出來后 直接入B庫,肯定是sql error,必須addslashes。如果要 serialize ,那么 serialize前無需addslashes,serialize后要,從數據庫中去出來的肯定是I'm,不是I'\m,serialize是好東西,但不要把addslashes后的也給serialize進去。
那么,我再繼續深一步,剛才說到了數據庫。
我們保證了入庫前的所有變量必須是addslashes,但是,如果你不做下面的一件事。那么你再addslashes也是白搭
哪件事呢?
select * from table where id=$id
select * from table where id=I\'m
看,依然sql錯誤,而且還被注入
我舉例子
沒錯,單引號封閉,無論你是什么類型的字段
在Discuz!的規范里,必須都加單引號
select * from table where id='$id'
WHERE后面的所有條件
變量必須加單引號,這是規范。也許你少加一個,并不會產生漏洞,也只是也許。
但,有些隱形的漏洞就是在七拐八拐中產生的。你少寫一個,那些黑客就會用七拐八拐的方式去分析,看看可否利用行中。
intval是必須的,規則也是必須遵守的,然后是html的問題,不要漏掉任何一個字串類型。
所有字串類型,如果你不希望他們顯示html,入庫前一定要htmlspecialchars后再入庫,或者strip_tags下
數字類型
大家都知道intval,字串是htmlspecialchars,當然,后臺無所謂!后臺比較安全,但是,最好也有,一個習慣,僅作參考。
$a = '12345';
$a_en = htmlspecialchars($a)
$a_ad = addslashes($a);
這樣,入庫的時候sql查詢語句里應該都是_ad結尾的
html模版中的應該都是_en結尾的
我說不出很多黑客的那些漏洞屬于
但是剛才說的那些如果都做到了,代碼安全不成問題
然后說說Discuz!內置的一些變量
Discuz!X中,理論上你要用 $_G ($_G['gp_*'] 除外) 里的變量,都要考慮htmlspecialchars和addslashes
$_G['gp_*'] 是DX里的GPC
GP
GET POST 都經過了 addslashes后存放到了$_G['gp_*]中
但_G中的其他,均沒addslashes
GPC都addslashes過
dhtmlspecialchars 支持數組
其他同理
如果你有一個良好的代碼規范,也會讓代碼安全性提高
很多規范大家可以給自己定,像剛才的$a_en $a_ad
第四點,下面簡單說說代碼規范
大家閱讀代碼的時候也許都看到了
$a = 1;
賦值語句前后空格
if(.........
if后面沒空格,這些細節涉及不到安全,但有一點,這些也有安全影響?
SQL
良好的代碼規范可增加自己的可讀性
DB::query("UPDATE ".DB::table('common_member_count')." set $giftunit = $remaining where uid = $_G[uid]");
Discuz!規定sql語句中的SQL關鍵詞必須大寫
DB::query("UPDATE ".DB::table('common_member_count')." SET $giftunit='$remaining' WHERE uid='$_G[uid]'");
修正過的
$giftunit = $remaining
沒引號,而且大小寫不明,閱讀起來很累,規范的不規范的寫在一起
雖然站長,不會看代碼。但是,一個漂亮代碼文檔,就像一篇好作文。
有一個SQL上的細節 notifications=notifications+1
這種SQL語句,理論上我們不推薦,雖然這么寫本身是正確的
如果a字段是unsigned類型,那么會產生數暴增
產生溢出
a=a+'-1'
就不會
mysql好奇怪的
這點大家通過pma試試就知道了
插件如有減分操作的時候
當a=0的時候
1、a=a-1
2、a=a+'-1'
3、a=a+(-1)
三種方法,你看哪個ok
下面說最后一點
涉及安全的,代碼的流程,你的程序,如果只在你的流程下運作
允許100、1000次也許都不會出錯。但是,在別人那里,不一定
舉例
foreach($array as $k => $v)
嗯,$array是數組,并且存在的時候。。。
沒錯,是,你自己調試的時候,這數組肯定有
但是在用戶那里,有可能就沒了
這時候,這語句有錯
如果$array不是數組的情況下,這句就錯了
你可以if(is_array($array))
也可以(array)$array
類似影響流程的不僅僅是foreach
如rawurlencode
echo rawurlencode('sss');
誰都知沒問題
但!!回到剛才我曾說過的,認清變量類型
echo rawurlencode(array('11'));
肯定出錯,大家可以測試下
因此 rawurlencode($s) 的時候
一定要確保$s是字串還是數組
用php的每一個函數的時候都要看清接受參數的類型
如果是字串,切記剛才說的
php很傻,有時候字串、數組不分
這是最后一點,爆路徑,爆路徑后能干啥,黑客最清楚
|
|