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