当浏览器重新加载/返回时,如何防止数据库被再次写入?

发布于 2024-07-09 08:33:46 字数 169 浏览 6 评论 0原文

我正在编写一个小型网络应用程序,用于写入数据库(Perl CGI 和 MySQL)。 CGI 脚本从表单中获取一些信息并将其写入数据库。 然而,我注意到,如果我在网络浏览器上点击“重新加载”或“返回”,它会再次将数据写入数据库。 我不想要这个。

在这种情况下,防止数据被重写的最佳方法是什么?

I'm putting together a small web app that writes to a database (Perl CGI & MySQL). The CGI script takes some info from a form and writes it to a database. I notice, however, that if I hit 'Reload' or 'Back' on the web browser, it'll write the data to the database again. I don't want this.

What is the best way to protect against the data being re-written in this case?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

莫多说 2024-07-16 08:33:47

每次更改数据时都执行 POST,但永远不要从帖子返回 HTML 响应...而是返回重定向到 GET,该 GET 检索更新的数据作为确认页面。 这样,就不用担心他们刷新页面了。 如果它们刷新,所发生的只是另一次检索,而不是数据更改操作。

Do a POST every time you alter data, but never return an HTML response from a post... instead return a redirect to a GET that retrieves the updated data as a confirmation page. That way, there is no worry about them refreshing the page. If they refresh, all that will happen is another retrieve, never a data-altering action.

荒人说梦 2024-07-16 08:33:46

不要使用 GET 请求进行修改! RESTful; 使用 POST(或 PUT)代替,浏览器应警告用户不要重新加载请求。 在 POST/ 后使用普通 GET 请求重定向(使用 HTTP 重定向)到收据页面PUT 请求将使刷新页面成为可能,而不会收到有关重新提交的警告。

编辑:

我假设用户以某种方式登录,因此您已经有了某种跟踪用户的方法,例如会话或类似的方法。

当显示将其存储为隐藏字段的表单时,您可以创建一个时间戳(或随机散列等...)(除了反跨站点请求令牌之外,我确信您已经准备好了 ),并且在会话变量(安全地存储在您的服务器上)中,当您收到此表单的 POST/PUT 请求时,您会检查时间戳是否与会话中的时间戳相同。 如果是,您可以将会话中的时间戳设置为某个变量且难以猜测(例如与某些秘密字符串连接的时间戳),然后您可以保存表单数据。 如果有人现在重复请求,您将不会在会话变量中找到相同的值并拒绝该请求。

这样做的问题是,如果用户单击返回来更改某些内容,则表单无效,并且可能有点苛刻,除非您要更新的是金钱。 因此,如果您遇到“愚蠢”用户刷新并单击后退按钮从而意外重新发布某些内容的问题,只需使用 POST 就会提醒他们不要这样做,而重定向会降低这种情况的可能性。 如果您遇到恶意用户的问题,您也应该使用时间戳,尽管它有时会让用户感到困惑,尽管如果用户故意一遍又一遍地发布相同的消息,您可能需要找到一种方法来禁止他们。 如果恶意用户只是编写一个脚本来自动加载表单并提交随机垃圾,那么使用 POST、设置时间戳,甚至对整个数据库进行全面比较来检查重复的帖子,都毫无帮助。 (但是跨站点请求保护使这变得更加困难)

Do not use GET requests to make modifications! Be RESTful; use POST (or PUT) instead the browser should warn the user not to reload the request. Redirecting (using HTTP redirection) to a receipt page using a normal GET request after a POST/PUT request will make it possible to refresh the page without getting warned about resubmitting.

EDIT:

I assume the user is logged in somehow, and therefore you allready have some way of tracking the user, e.g. session or similar.

You could make a timestamp (or a random hash etc..) when displaying the form storing it both as a hidden field (just besides the anti Cross-Site Request token I'm sure you allready have there), and in a session variable (wich is stored safely on your server), when you recieve a the POST/PUT request for this form, you check that the timestamp is the same as the one in session. If it is, you set the timestamp in the session to something variable and hard to guess (timestamp concatenated with some secret string for instance) then you can save the form data. If someone repeats the request now you won't find the same value in the session variable and deny the request.

The problem with doing this is that the form is invalid if the user clicks back to change something, and it might be a bit to harsh, unless it's money you're updating. So if you have problems with "stupid" users who refresh and click the back-button thus accidentally reposting something, just using POST would remind them not to do that, and redirecting will make it less likely. If you have a problem with malicious users, you should use a timestampt too allthough it will confuse users sometimes, allthough if users is deliberately posting the same message over and over you probably need to find a way to ban them. Using POST, having a timestam, and even doing a full comparison of the whole database to check for duplicate posts, won't help at all if the malicious users just write a script to load the form and submit random garbage, automatically. (But cross-site-request protection makes that a lot harder)

恬淡成诗 2024-07-16 08:33:46

使用 POST 请求将导致浏览器尝试阻止用户再次提交相同的请求,但我建议使用某种基于会话的事务跟踪,以便用户忽略浏览器的警告并重新提交其查询您的应用程序将防止对数据库进行重复更改。 您可以在提交表单中包含一个隐藏输入,并将值设置为加密哈希值,并在提交和处理请求没有错误的情况下记录该哈希值。

Using a POST request will cause the browser to try to prevent the user from submitting the same request again, but I'd recommend using session-based transaction tracking of some kind so that if the user ignores the warnings from the browser and resubmits his query your application will prevent duplication of changes to the database. You could include a hidden input in the submission form with value set to a crypto hash and record that hash if the request is submitted and processed without error.

故事还在继续 2024-07-16 08:33:46

我发现跟踪用户在会话中执行的表单提交数量很方便。 然后,在渲染表单时,我创建一个包含该数字的隐藏字段。 如果用户然后通过按后退按钮重新提交表单,它将提交旧的 # 并且服务器可以通过检查会话中的内容和表单的内容来判断用户已经提交了表单。

只是我的2分钱。

I find it handy to track the number of form submissions the user has performed in their session. Then when rendering the form I create a hidden field that contains that number. If the user then resubmits the form by pressing the back button it'll submit the old # and the server can tell that the user has already submitted the form by examining what's in the session to what the form is saying.

Just my 2 cents.

执手闯天涯 2024-07-16 08:33:46

如果您还没有使用某种会话管理(这可以让您记录和跟踪表单提交),一个简单的解决方案是在表单中包含某种唯一标识符(作为隐藏元素),该标识符是任一部分主数据库事务本身,或在单独的数据库表中跟踪。 然后,当您提交表单时,您会检查唯一 ID 以查看它是否已被处理。 每次呈现表单本身时,您只需确保拥有唯一的 ID 即可。

If you aren't already using some sort of session-management (which would let you note and track form submissions), a simple solution would be to include some sort of unique identifier in the form (as a hidden element) that is either part of the main DB transaction itself, or tracked in a separate DB table. Then, when you are submitted a form you check the unique ID to see if it has already been processed. And each time the form itself is rendered, you just have to make sure you have a unique ID.

揪着可爱 2024-07-16 08:33:46

首先,你不能信任浏览器,所以任何关于使用 POST 而不是 GET 的讨论大多都是书呆子的胡言乱语。 是的,客户可能会收到类似“您是否打算再次重新提交此数据?”的警告,但他们很可能会说“是的,现在别打扰我,愚蠢的计算机”。

正确的是:如果您不想重复提交,那么要解决的是您的问题,而不是用户的问题。

您想必知道重复提交意味着什么。 也许是几秒钟内的同一个IP,也许是同一篇博客文章的标题或最近提交的一个URL。 也许它是值的组合 - 例如 IP 地址、电子邮件地址和提交的联系表单的主题标题。 无论哪种方式,如果您手动发现数据中的一些重复项,您应该能够找到一种在提交时以编程方式识别重复项的方法,并将其标记为手动批准(如果您不确定),或者只是告诉提交者“你双击了吗?” (如果信息不是极其机密,您可以出示您为他们提供的现有记录并说“这是您打算发送给我们的信息吗?如果是这样,您已经完成了 - 万岁”)

First of all, you can't trust the browser, so any talk about using POST rather than GET is mostly nerd flim-flam. Yes, the client might get a warning along the lines of "Did you mean to resubmit this data again?", but they're quite possibly going to say "Yes, now leave me alone, stupid computer".

And rightly so: if you don't want duplicate submissions, then it's your problem to solve, not the user's.

You presumably have some idea what it means to be a duplicate submission. Maybe it's the same IP within a few seconds, maybe it's the same title of a blog post or a URL that has been submitted recently. Maybe it's a combination of values - e.g. IP address, email address and subject heading of a contact form submission. Either way, if you've manually spotted some duplicates in your data, you should be able to find a way of programmatically identifying a duplicate at the time of submission, and either flagging it for manual approval (if you're not certain), or just telling the submitter "Have you double-clicked?" (If the information isn't amazingly confidential, you could present the existing record you have for them and say "Is this what you meant to send us? If so, you've already done it - hooray")

℉服软 2024-07-16 08:33:46

我不会依赖浏览器的 POST 警告。 用户只需单击“确定”即可让消息消失。

任何时候你都会有一个只需要一次的请求,例如“付款”,发送一个唯一的令牌,该令牌会随请求一起提交回来。 返回后将令牌扔掉,这样您现在就可以判断何时提交内容有效(任何带有非“活动”令牌的内容)。 X 时间后(例如,当用户会话结束时)使活动令牌过期。

(或者跟踪已返回的令牌,如果您之前收到过该令牌,则该令牌无效。)

I'd not rely on POST warnings from the browser. Users just click OK to make messages go away.

Anytime you'll have a request that needs to be one time only e.g 'make a payment', send a unique token down, that gets submitted back with the request. Throw the token out after it comes back, and so you can now tell when something is a valid submission (anything with a token that isn't 'active'). Expire active tokens after X amount of time, e.g. when a user session ends.

(alternately track the tokens that have come back, and if you have received it before then it is invalid.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文