溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何在PHP中使用timestamp和nonce防止重放攻擊

發(fā)布時(shí)間:2021-02-05 17:48:07 來(lái)源:億速云 閱讀:243 作者:Leah 欄目:開(kāi)發(fā)技術(shù)

這篇文章將為大家詳細(xì)講解有關(guān)如何在PHP中使用timestamp和nonce防止重放攻擊,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

基于timestamp的方案

每次HTTP請(qǐng)求,都需要加上timestamp參數(shù),然后把timestamp和其他參數(shù)一起進(jìn)行數(shù)字簽名。因?yàn)橐淮握5腍TTP請(qǐng)求,從發(fā)出到達(dá)服務(wù)器一般都不會(huì)超過(guò)60s,所以服務(wù)器收到HTTP請(qǐng)求之后,首先判斷時(shí)間戳參數(shù)與當(dāng)前時(shí)間相比較,是否超過(guò)了60s,如果超過(guò)了則認(rèn)為是非法的請(qǐng)求。

假如黑客通過(guò)抓包得到了我們的請(qǐng)求url:
http://koastal.site/index/Info?uid=ZX07&stime=1480862753&sign=80b886d71449cb33355d017893720666

其中

$sign=md5($uid.$token.$stime);
// 服務(wù)器通過(guò)uid從數(shù)據(jù)庫(kù)中可讀出token

一般情況下,黑客從抓包重放請(qǐng)求耗時(shí)遠(yuǎn)遠(yuǎn)超過(guò)了60s,所以此時(shí)請(qǐng)求中的stime參數(shù)已經(jīng)失效了。
如果黑客修改stime參數(shù)為當(dāng)前的時(shí)間戳,則sign參數(shù)對(duì)應(yīng)的數(shù)字簽名就會(huì)失效,因?yàn)楹诳筒恢纓oken值,沒(méi)有辦法生成新的數(shù)字簽名。

但這種方式的漏洞也是顯而易見(jiàn)的,如果在60s之內(nèi)進(jìn)行重放攻擊,那就沒(méi)辦法了,所以這種方式不能保證請(qǐng)求僅一次有效。

基于nonce的方案

nonce的意思是僅一次有效的隨機(jī)字符串,要求每次請(qǐng)求時(shí),該參數(shù)要保證不同,所以該參數(shù)一般與時(shí)間戳有關(guān),我們這里為了方便起見(jiàn),直接使用時(shí)間戳的16進(jìn)制,實(shí)際使用時(shí)可以加上客戶端的ip地址,mac地址等信息做個(gè)哈希之后,作為nonce參數(shù)。
我們將每次請(qǐng)求的nonce參數(shù)存儲(chǔ)到一個(gè)“集合”中,可以json格式存儲(chǔ)到數(shù)據(jù)庫(kù)或緩存中。
每次處理HTTP請(qǐng)求時(shí),首先判斷該請(qǐng)求的nonce參數(shù)是否在該“集合”中,如果存在則認(rèn)為是非法請(qǐng)求。

假如黑客通過(guò)抓包得到了我們的請(qǐng)求url:
http://koastal.site/index/Info?uid=ZX07&nonce=58442c21&sign=80b886d71449cb33355d017893720666

其中

$sign=md5($uid.$token.$nonce);
// 服務(wù)器通過(guò)uid從數(shù)據(jù)庫(kù)中可讀出token

nonce參數(shù)在首次請(qǐng)求時(shí),已經(jīng)被存儲(chǔ)到了服務(wù)器上的“集合”中,再次發(fā)送請(qǐng)求會(huì)被識(shí)別并拒絕。
nonce參數(shù)作為數(shù)字簽名的一部分,是無(wú)法篡改的,因?yàn)楹诳筒磺宄oken,所以不能生成新的sign。

這種方式也有很大的問(wèn)題,那就是存儲(chǔ)nonce參數(shù)的“集合”會(huì)越來(lái)越大,驗(yàn)證nonce是否存在“集合”中的耗時(shí)會(huì)越來(lái)越長(zhǎng)。我們不能讓nonce“集合”無(wú)限大,所以需要定期清理該“集合”,但是一旦該“集合”被清理,我們就無(wú)法驗(yàn)證被清理了的nonce參數(shù)了。也就是說(shuō),假設(shè)該“集合”平均1天清理一次的話,我們抓取到的該url,雖然當(dāng)時(shí)無(wú)法進(jìn)行重放攻擊,但是我們還是可以每隔一天進(jìn)行一次重放攻擊的。而且存儲(chǔ)24小時(shí)內(nèi),所有請(qǐng)求的“nonce”參數(shù),也是一筆不小的開(kāi)銷(xiāo)。

基于timestamp和nonce的方案

那我們?nèi)绻瑫r(shí)使用timestamp和nonce參數(shù)呢?
nonce的一次性可以解決timestamp參數(shù)60s的問(wèn)題,timestamp可以解決nonce參數(shù)“集合”越來(lái)越大的問(wèn)題。

我們?cè)趖imestamp方案的基礎(chǔ)上,加上nonce參數(shù),因?yàn)閠imstamp參數(shù)對(duì)于超過(guò)60s的請(qǐng)求,都認(rèn)為非法請(qǐng)求,所以我們只需要存儲(chǔ)60s的nonce參數(shù)的“集合”即可。

假如黑客通過(guò)抓包得到了我們的請(qǐng)求url:
http://koastal.site/index/Info?uid=ZX07&stime=1480862753&nonce=58442c21&sign=80b886d71449cb33355d017893720666

其中

$sign=md5($uid.$token.$stime.$nonce);
// 服務(wù)器通過(guò)uid從數(shù)據(jù)庫(kù)中可讀出token

如果在60s內(nèi),重放該HTTP請(qǐng)求,因?yàn)閚once參數(shù)已經(jīng)在首次請(qǐng)求的時(shí)候被記錄在服務(wù)器的nonce參數(shù)“集合”中,所以會(huì)被判斷為非法請(qǐng)求。超過(guò)60s之后,stime參數(shù)就會(huì)失效,此時(shí)因?yàn)楹诳筒磺宄oken的值,所以無(wú)法重新生成簽名。

綜上,我們認(rèn)為一次正常的HTTP請(qǐng)求發(fā)送不會(huì)超過(guò)60s,在60s之內(nèi)的重放攻擊可以由nonce參數(shù)保證,超過(guò)60s的重放攻擊可以由stime參數(shù)保證。

因?yàn)閚once參數(shù)只會(huì)在60s之內(nèi)起作用,所以只需要保存60s之內(nèi)的nonce參數(shù)即可。

我們并不一定要每個(gè)60s去清理該nonce參數(shù)的集合,只需要在新的nonce到來(lái)時(shí),判斷nonce集合最后一次修改時(shí)間,超過(guò)60s的話,就清空該集合,存放新的nonce參數(shù)集合。其實(shí)nonce參數(shù)集合可以存放的時(shí)間更久一些,但是最少是60s。
隨機(jī)數(shù)集合可以根據(jù)業(yè)務(wù)場(chǎng)景采用定期清理或根據(jù)大小自動(dòng)清理的方案,例如該接口每秒的請(qǐng)求數(shù)最高為1000,則60s內(nèi)的請(qǐng)求數(shù)量最多為1500*60=90000,則我們?cè)诿看握?qǐng)求后檢查集合大小是否超過(guò)90000,若超高該數(shù)量則清空。

驗(yàn)證流程

//判斷stime參數(shù)是否有效
if( $now - $stime > 60){
  die("請(qǐng)求超時(shí)");
}
//判斷nonce參數(shù)是否在“集合”已存在
if( in_array($nonce,$nonceArray) ){
  die("請(qǐng)求僅一次有效");
}
//驗(yàn)證數(shù)字簽名
if ( $sign != md5($uid.$token.$stime.$nonce) ){
  die("數(shù)字簽名驗(yàn)證失敗");
}
/*
if( $now - $nonceArray->lastModifyTime > 60 ){
  $nonceArray = null;
}
$nonceArray.push($nonce);
*/
//處理隨機(jī)數(shù)
$key = 'nonce'+$uid;
if($redis->sismember($key,$nonce) === true){
  die('拒絕重放攻擊請(qǐng)求');
}
if($redis->scard($key) > 90000){
  $redis->del($key);
}
$redis->sadd($key,$nonce);
//重放攻擊檢查完成

關(guān)于如何在PHP中使用timestamp和nonce防止重放攻擊就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI