2008-11-20 33 views
5

我正在編寫一個寫入數據庫的小型web應用程序(Perl CGI & MySQL)。 CGI腳本從表單獲取一些信息並將其寫入數據庫。但是,我注意到,如果我在Web瀏覽器上點擊「重新加載」或「返回」,它會再次將數據寫入數據庫。我不想要這個。當瀏覽器重新加載/返回時,如何防止再次寫入數據庫?

在這種情況下防止數據被重寫的最佳方法是什麼?

回答

17

請勿使用GET請求進行修改!是RESTful;使用POST(或PUT),而瀏覽器應警告用戶不要重新加載請求。在POST/PUT請求後,使用普通的GET請求將接收頁面重定向到(using HTTP redirection)將使刷新頁面成爲可能,而不會收到有關重新提交的警告。

編輯:

我承擔某種方式在用戶登錄,因此,你有媒體鏈接跟蹤用戶的,例如某種方式會話或類似的。

當顯示存儲爲隱藏字段的表單時(除了反跨站點請求標記我相信你已經在那裏了),你可以做一個時間戳(或隨機哈希等..) ,並在一個會話變量(這是安全地存儲在您的服務器上),當您收到此表單的POST/PUT請求時,您檢查時間戳與會話中的時間戳相同。如果是這樣,您將會話中的時間戳設置爲某個變量並且難以猜測(時間戳與例如某個祕密字符串連接),那麼您可以保存表單數據。如果有人現在重複請求,您將無法在會話變量中找到相同的值並拒絕該請求。

這樣做的問題在於,如果用戶點擊返回以更改某些內容,則表單無效,並且可能會有點苛刻,除非它是您更新的資金。因此,如果您對刷新並單擊後退按鈕因而意外重新發布某些內容的「愚蠢」用戶遇到問題,則只需使用POST即可提醒他們不要這樣做,重定向將使其不太可能。如果你有惡意用戶的問題,你也應該使用時間戳,雖然它有時會讓用戶感到困惑,但如果用戶故意一遍又一遍地發佈相同的消息,你可能需要找到一種方法來禁止它們。如果惡意用戶只是編寫一個腳本來自動加載表單並提交隨機垃圾,那麼使用POST,具有時間戳,甚至對整個數據庫進行全面比較以檢查重複的帖子都無濟於事。 (但是跨站點請求保護使得難度更大)

+0

該OP正在抱怨他的用戶弄亂了系統。說「讓他們的瀏覽器嘗試並阻止他們」幾乎不是解決問題的鑄鐵解決方案。 – 2008-11-22 03:13:52

+2

不,但它使良性用戶不太可能這樣做,我添加了一些想法來進一步減少問題。 – 2008-11-22 10:47:39

4

我發現它很方便跟蹤用戶在會話中執行的表單提交數量。然後,在呈現表單時,我創建一個包含該數字的隱藏字段。如果用戶通過按下後退按鈕重新提交表單,它會提交舊的#,並且服務器可以通過檢查會話中的內容以及表單的內容來告訴用戶已經提交了表單。

只是我2美分。

6

使用POST請求將導致瀏覽器,試圖阻止用戶再次提交相同的請求,但我建議你使用某種基於會話的交易追蹤,這樣,如果用戶忽略來自瀏覽器的警告並重新提交他的查詢,你的應用程序將防止重複數據庫的更改。您可以在提交表單中包含一個隱藏的輸入,並將其值設置爲加密哈希,並在請求提交併處理時沒有錯誤地記錄該哈希。

1

如果您還沒有使用某種會話管理(可以讓您記錄並跟蹤表單提交),一個簡單的解決方案是在表單中包含某種唯一標識符(作爲隱藏元素)這是主要數據庫事務本身的一部分,或者在單獨的數據庫表中進行跟蹤。然後,當您提交表單時,請檢查唯一ID以查看是否已處理。每次表單呈現時,您都必須確保您擁有唯一的ID。

+0

您發出一個票號,然後只打一次票。 – dkretz 2008-11-21 02:12:23

1

首先,你不能相信瀏覽器,所以任何關於使用POST而不是GET的討論大部分都是書呆子flim-flam。是的,客戶可能會按照「你是否想再次重新提交這些數據?」這樣的問題發出警告,但他們很可能會說「是的,現在讓我一個人呆着,笨拙的電腦」。

而且的確如此:如果您不希望重複提交,那麼這是您解決問題的問題,而不是用戶的問題。

你大概有一些想法是什麼意思是重複提交。也許它在幾秒鐘內就是同一個IP地址,也許它是一個博客文章的標題或最近提交的URL。也許它是價值的組合 - 例如IP地址,電子郵件地址和提交聯繫表格的主題。無論哪種方式,如果您手動在數據中發現了一些重複項,您應該能夠在提交時找到以編程方式標識重複項的方法,並將其標記爲手動批准(如果您不確定),或者只是告訴提交者「你有雙擊嗎?」 (如果信息不是非常機密,你可以提供你現有的記錄,並說「這是你要發給我們的嗎?如果是這樣,你已經做到了 - 萬歲」)

1

我不要依賴瀏覽器的POST警告。用戶只需點擊確定即可讓信息消失。

無論何時您只需要一次請求,例如'付款',就發送一個唯一的令牌,然後將請求提交回來。在返回後丟棄該標記,因此現在可以知道何時是有效的提交(任何標記不是「有效」的)。在X時間後(例如,當用戶會話結束時。

(交替跟蹤已經回來了令牌,如果你在此之前收到它,它是無效的。)

0

做一個POST在您每次修改數據的時間,但永遠不會返回從帖子的HTML響應。 ..而是返回一個重定向到一個獲取更新數據的GET作爲確認頁面。這樣,就不用擔心刷新頁面。如果它們刷新,所有將發生的是另一次檢索,而不是數據更改操作。

相關問題