我正在整理一个写入数据库的小型Web应用程序(Perl CGI和MySQL).CGI脚本从表单中获取一些信息并将其写入数据库.但是,我注意到,如果我在网络浏览器上点击"重新加载"或"返回",它会再次将数据写入数据库.我不想要这个.
在这种情况下,防止重写数据的最佳方法是什么?
不要使用GET请求进行修改!保持安静 ; 使用POST(或PUT)代替浏览器应警告用户不要重新加载请求.在POST/PUT请求之后使用普通GET请求将(使用HTTP重定向)重定向到收据页面将使刷新页面成为可能,而不会收到有关重新提交的警告.
编辑:
我假设用户以某种方式登录,因此您已经有一些跟踪用户的方式,例如会话或类似.
您可以在显示表单时创建时间戳(或随机哈希等...),将其存储为隐藏字段(除了反交叉站点请求令牌,我确定您已经存在),以及会话变量(安全地存储在您的服务器上),当您收到此表单的POST/PUT请求时,您检查时间戳是否与会话中的时间戳相同.如果是,则将会话中的时间戳设置为变量且难以猜测(例如,时间戳与某些秘密字符串连接),然后您可以保存表单数据.如果有人现在重复请求,您将在会话变量中找不到相同的值并拒绝该请求.
这样做的问题是,如果用户点击返回更改某些内容,则表单无效,并且可能有点苛刻,除非您正在更新这些钱.因此,如果您遇到"愚蠢"用户的问题,他们刷新并单击后退按钮,从而意外地重新发布内容,只需使用POST就会提醒他们不要这样做,重定向将使其不太可能.如果你有恶意用户的问题,你应该使用时间戳,虽然它有时会使用户感到困惑,但是如果用户故意在一遍又一遍地发布相同的消息你可能需要找到一种方法来禁止它们.使用POST,拥有一个timestam,甚至对整个数据库进行全面比较以检查重复的帖子,赢得了' 如果恶意用户只是编写脚本来加载表单并自动提交随机垃圾,则可以提供帮助.(但跨站点请求保护使得更难)
使用POST请求将导致浏览器尝试阻止用户再次提交相同的请求,但我建议使用某种基于会话的事务跟踪,以便用户忽略来自浏览器的警告并重新提交其查询您的应用程序将防止重复更改数据库.您可以在提交表单中包含隐藏输入,并将值设置为加密哈希值,并在提交和处理请求时无错误地记录该哈希值.