0
對於使用PHP編寫的應用程序中的「確認訂單」頁面,我需要阻止多個表單提交,因此我們不會獲得重複的訂單。我試圖通過兩種方式來處理這個問題:即使使用CSRF令牌,表單提交中的PHP重複訂單
- 對於用戶JavaScript支持提交按鈕上點擊
- 令牌與形式產生的禁用和存儲在會話。在第一次提交時,他們被比較,會話令牌被刪除。因此,沒有匹配標記的後續提交應該被拒絕。這應該有防止CSRF攻擊的額外好處。
我明白,兩者都是相當標準的做法,但問題似乎仍然存在?如果我點擊提交按鈕幾次,js被禁用,我將得到X個重複訂單。
這讓我覺得可能是問題是配置相關。它位於lighthttpd上,php是用cgi-fcgi編譯的。我並不完全確定這是否有意義,但我對此感到困惑。
服務器代碼如下(上剪下來的簡潔):
<?php
$_SESSION['token'] = uniqid('', true);
?>
<form name="myform" action="confirm" method="POST">
<!--.... -->
<input type="hidden" name="csrftoken" value="<?php echo $_SESSION['token']; ?>" />
<input type="submit" name="submit" />
然後在提交令牌驗證:
<?php
if ($_POST['csrftoken'] == $_SESSION['token']) {
//proceed and process order
unset($_SESSION['token']);
}
?>
會話開始和令牌正確生成並隨後取消設置。
我以前用過這種方法沒有問題,但這一次它似乎仍然通過。希望有任何見解。
保持會話儘可能短並強制使用'session_write_close()'進行保存。使用'$ _SESSION'輸出html是一種糟糕的做法。在本地var然後釋放會話中複製需要的會話數據。 – Ghigo 2013-03-20 08:52:41
謝謝。該應用程序是一個遺留應用程序,我正在修復一個錯誤。我通常不會在HTML輸出中引用$ _SESSION。 缺少session_write_close確實是問題的一部分。問題在於原始表單提交發生在鎖定會話的iframe中,因此它不會被取消設置。使用session_write_close確實解決了這個問題,但是引入了後續會話更改未被正確更新的進一步問題,即使隨後使用了session_start。 – 2013-03-21 08:40:54
應對代碼進行重構,以便在session_start()和session_write_close()之間進行所有$ _SESSION訪問。我知道遺留代碼必須工作,所以你可以考慮一個相當醜陋的黑客攻擊:在'session_write_close()'之後搜索所有$ _SESSION訪問權限,重新打開會話,修改會話數據並再次關閉它。當然不好的表現,但它應該做的伎倆。 – Ghigo 2013-03-21 09:46:55