如何防止用户重新提交表单?

3
我正在开发一个单页应用程序。
在应用程序的末尾,用户需要提交他的联系信息(姓名、电话号码等)。这将发送一封电子邮件并将页面修改为“感谢提交[...]”页面。
问题是,客户端可以按下“返回”按钮并重新发送电子邮件。
有没有方法来防止这种垃圾邮件?

代码

Sub BT_Send(sender As Object, e As EventArgs) Handles BT_Send.Click
Try
    'Creating the Email Message
    Dim mailMessage As New MailMessage()
    mailMessage.To.Add("SomeOne@a.com")
    mailMessage.From = New MailAddress("Robot@a.com", "Robot")
    mailMessage.Subject = "Test"
    mailMessage.IsBodyHtml = True
    mailMessage.Body = LBL_Emailbody.Text & _
        "<br><br><br><div style=""font-size: 0.7em;"">Robot speaking, I will not answer if you send me a message.</div>"
    Dim smtpClient As New SmtpClient("Something.com")
    smtpClient.Send(mailMessage)


    PNL_Before.Visible = False
    PNL_After.Visible = True
Catch ex As Exception
    LBL_errorEmail.Visible = True
    'Should never happen...
End Try
End sub

1
你可以存储一个cookie来表示用户已经使用了表单,当检测到该cookie时,不允许进入该表单。 - fahadash
有一些方法可以做到这一点,你可以保存用户最近发送的最后一封电子邮件,并避免在时间上过于接近的情况下重新发送联系人。 - Aristos
@Aristos 最后的电子邮件要保存在哪里?(如果您的意思是将其保存在接收端,则他仍然可以发送它。如果使用cookie,则用户可以禁用cookie并仍然执行此操作) - Sifu
@Aristos 现在你让它变得更有趣了。你正在存储静态数据?这首先是不推荐的,因为它具有应用程序级别的范围。如果另一个用户正在尝试发送类似的电子邮件,那该怎么办? - fahadash
@Sifu 这取决于您的用户群,有多少百分比的用户可能会尝试“黑客”方式来重复提交您的表单?如果您的系统容易受到喜欢玩弄安全性的技术宅的攻击,那么是的,您应该花时间完善它。否则,请问自己,这值得您花费时间吗? - fahadash
显示剩余3条评论
1个回答

2

这是一个非常简单的例子,我在页面上使用静态变量来避免使用数据库。

这个asp.net页面是:

<asp:Literal runat="server" ID="txtInfos"></asp:Literal><br />
<asp:TextBox runat="server" ID="txtEmail"></asp:TextBox><br />
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />/>

以及背后的代码。

static Dictionary<string, DateTime> cLastSubmits = new Dictionary<string, DateTime>();

private static readonly object syncLock = new object();

protected void Button1_Click(object sender, EventArgs e)
{
    DateTime cWhenLast;

    lock (syncLock)
    {
        var cNowIs = DateTime.UtcNow;
        if (cLastSubmits.TryGetValue(txtEmail.Text, out cWhenLast))
        {
            if (cWhenLast > cNowIs )
            {
                txtInfos.Text = "Please contact us again after 10 seconds";
                return;
            }
            else
            {
                // ok I let him submit the form, but note the last date time.
                cLastSubmits.Remove(txtEmail.Text);
            }
        }

        foreach(var DelMe in cLastSubmits.Where(x => cNowIs > x.Value).ToList())
            cLastSubmits.Remove(DelMe.Key);

        // if reach here, note the last datetime of submit            
        cLastSubmits.Add(txtEmail.Text, cNowIs.AddSeconds(10));
    }

    // and submit the form.
    txtInfos.Text = "thank you for submit the form";
}

一些笔记。

  • 如果您有许多池(Web花园),那么这可能会使用户在同时提交的情况下,向您拥有的池提交数据。
  • 当然,如果用户提交虚假数据,这无法保护您,因此我们可以使用:

    1. 蜜罐技术
    2. 验证码
    3. 其他控件识别机器人
    4. 代码识别重新提交

非常有趣!我已经知道了honey pot trickcaptcha。作为用户,我不需要保护自己免受机器人的攻击,因为用户必须使用验证的电子邮件帐户注册才能发送电子邮件。我正在尝试理解dictionaries,但我似乎无法理解它存储在哪里?(因为在每次回发时,所有变量都为空) - Sifu
@师傅,我已经更新了代码以清除旧数据。看,我将其设置为静态变量,这样它会存储在 asp.net 池的全局数据中。 - Aristos
@Sifu 试试吧,很酷而且能用 :) 我已经制作并测试过了。 - Aristos
我明白了!谢谢你抽出时间写这个。我会用它来防止多次发送。 - Sifu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接