《安全:PHP防止站外表單跨站提交的幾種辦法詳解》要點(diǎn):
本文介紹了安全:PHP防止站外表單跨站提交的幾種辦法詳解,希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
相關(guān)主題:PHP開(kāi)發(fā) / PHP安全
在眾多功擊手段中,有一種是功擊者自己偽造了一個(gè)和你網(wǎng)站一樣的表單,然后在他自己站內(nèi)或別處,向你的網(wǎng)站提交。
這種跨站和XSS不一樣,是為了提交表單數(shù)據(jù)到你的網(wǎng)站,給安全造成了問(wèn)題。
對(duì)于這類(lèi)的功擊,有幾種方式:
1、傳統(tǒng)的淺層阻止:這個(gè)是最常用的。但是其實(shí)根本沒(méi)用
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : NULL; $host = $_SERVER['HTTP_HOST']; echo '提交過(guò)來(lái)的地址:'.$referer; echo '<br>本站域名:'.$host; echo substr($referer,7,strlen($host)); if(substr($referer,7,strlen($host)) != $host){ echo '非法操作'; }else{ echo '正常操作'; }
因?yàn)镽EFERER可以偽造。所以沒(méi)有意義。
2、加密令牌:
很多CMS會(huì)用到這個(gè)方式,就是生成一個(gè)隨機(jī)串,比如VEPHP , 然后隨表單生成一個(gè)隱藏域<input type="hidden" value="vephp" name="chk" /> 并把這個(gè)值保存到服務(wù)器的SESSION上。
等到用戶(hù)提交后,檢查這個(gè)表單值和SESSION對(duì)比,不符就阻止。
不過(guò),這個(gè)方式如果用戶(hù)多的話(huà),會(huì)造成大量的SESSION,消耗服務(wù)器資源。不推薦。一種優(yōu)化的方式是把這個(gè)口令放在CACHE系統(tǒng)中,但是因?yàn)榫彺鏁?huì)不定時(shí)清除,所以也有問(wèn)題。
3、加密方式:
推薦這種方式:分為單向加密和可逆向加密。
就是生成一個(gè)隨機(jī)且變換頻繁加密字符串(可逆和不可逆)。跟方式2一樣放在表單中。等到表單提交后檢查。
這個(gè)隨機(jī)字符串如果和當(dāng)前用戶(hù)身份相關(guān)聯(lián)的話(huà),那么攻擊者偽造請(qǐng)求會(huì)比較麻煩。
對(duì)付偽造跨站請(qǐng)求的辦法是在表單里加入一個(gè)叫.crumb的隨機(jī)串;而facebook也有類(lèi)似的解決辦法,它的表單里常常會(huì)有post_form_id和fb_dtsg。這種方式中,字符串的有效時(shí)間要設(shè)置好,太短了用戶(hù)體驗(yàn)不好,比如好不容易寫(xiě)好文章提交,令牌卻到期了。不得不重寫(xiě),這很糟糕的體驗(yàn)。因此,TTL過(guò)期時(shí)間應(yīng)可設(shè)置。
下面是一個(gè)網(wǎng)上的不可逆的驗(yàn)證方式,值的推薦:
class Crumb { CONST SALT = "http://www.snjht.com"; static $ttl = 7200; #很重要,不要太短,看表單用途修改issueCrumb()過(guò)期時(shí)間 /** 生成加密串,可以添加到表單中 * @param $uid 用戶(hù)ID * @param int $action * @return bool|string */ static public function issueCrumb($uid, $ttl=7200, $action = -1) { if(intval($ttl)>7200) self::$ttl = $ttl; $i = ceil(time() / self::$ttl); return substr(self::challenge($i . $action . $uid), -12, 10); } /** 解密 * @param $uid * @param $crumb 加密時(shí) Crumb::issueCrumb($uid)生成的字串。 * @param int $action * @return bool */ static public function verifyCrumb($uid, $crumb, $action = -1) { $i = ceil(time() / self::$ttl); if(substr(self::challenge($i . $action . $uid), -12, 10) == $crumb || substr(self::challenge(($i - 1) . $action . $uid), -12, 10) == $crumb) return true; return false; } //內(nèi)用 static public function challenge($data) { return hash_hmac('md5', $data, self::SALT); } }
使用:
在表單中插入一個(gè)隱藏的隨機(jī)串crumb,其中,$uid可以是會(huì)員的ID,這樣就有獨(dú)立性。
<input type="hidden" name="crumb" value="<?php echo Crumb::issueCrumb($uid)?>">
在PHP服務(wù)器接收端,這樣檢驗(yàn)。默認(rèn)下這個(gè)字串的有效期是7200秒。
<?php if(!Crumb::verifyCrumb($uid, $_POST['crumb'])) echo "驗(yàn)證失敗";
上面這種是不可逆的加密,
有時(shí),我們還希望在表單中加入私密數(shù)據(jù),跟隨用戶(hù)表單加密串一直生成,在前端不被用戶(hù)看到,這樣就可以用到可解密的函數(shù),生成的字串在PHP端解密,起到2個(gè)作用:
1、得到私密數(shù)據(jù)。
2、驗(yàn)證表單來(lái)源的合法性。
我推薦可逆的加密方式。
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.snjht.com/jiaocheng/61.html