2013-03-20 34 views
0

對於使用PHP編寫的應用程序中的「確認訂單」頁面,我需要阻止多個表單提交,因此我們不會獲得重複的訂單。我試圖通過兩種方式來處理這個問題:即使使用CSRF令牌,表單提交中的PHP重複訂單

  1. 對於用戶JavaScript支持提交按鈕上點擊
  2. 令牌與形式產生的禁用和存儲在會話。在第一次提交時,他們被比較,會話令牌被刪除。因此,沒有匹配標記的後續提交應該被拒絕。這應該有防止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']); 
    } 

?> 

會話開始和令牌正確生成並隨後取消設置。

我以前用過這種方法沒有問題,但這一次它似乎仍然通過。希望有任何見解。

+1

保持會話儘可能短並強制使用'session_write_close()'進行保存。使用'$ _SESSION'輸出html是一種糟糕的做法。在本地var然後釋放會話中複製需要的會話數據。 – Ghigo 2013-03-20 08:52:41

+0

謝謝。該應用程序是一個遺留應用程序,我正在修復一個錯誤。我通常不會在HTML輸出中引用$ _SESSION。 缺少session_write_close確實是問題的一部分。問題在於原始表單提交發生在鎖定會話的iframe中,因此它不會被取消設置。使用session_write_close確實解決了這個問題,但是引入了後續會話更改未被正確更新的進一步問題,即使隨後使用了session_start。 – 2013-03-21 08:40:54

+0

應對代碼進行重構,以便在session_start()和session_write_close()之間進行所有$ _SESSION訪問。我知道遺留代碼必須工作,所以你可以考慮一個相當醜陋的黑客攻擊:在'session_write_close()'之後搜索所有$ _SESSION訪問權限,重新打開會話,修改會話數據並再次關閉它。當然不好的表現,但它應該做的伎倆。 – Ghigo 2013-03-21 09:46:55

回答

0

繼Ghigo的評論後,我重構了代碼來完成這項工作。

這個問題最終是從iframe和表單提交會話鎖定的問題。確保會議儘早結束是解決這個問題的關鍵。

相關問題