3

I am developping a Single Page Application.

At the end of the application, the user gets to submit his contact information (name, phone number, etc). This sends an Email and modifies the page to a "Thanks for submitting [...]" page.

The problem is, the client can press the Back button and REsend the Email.

Is there a way to prevent this sort of.. spam?

Code

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
Sifu
  • 1,082
  • 8
  • 26
  • 1
    You can store a cookie to indicate user has already used the form and when you detect that cookie, do not allow the form. – fahadash Jul 30 '14 at 15:06
  • There are some ways... you can keep the last email that user have been send, and avoid to resend very close in time contacts. – Aristos Jul 30 '14 at 15:06
  • @fahadash What if the user has cookies disabled? – Sifu Jul 30 '14 at 15:08
  • @Aristos Keep the last email **where**? (If you mean keep it in the receiving end, then he still gets to send it.. If it is with a cookie, the user can disable cookies and still do it) – Sifu Jul 30 '14 at 15:09
  • You can keep them on a database, if you do not have database one fast easy way is on a static variable (eg on dictionary). The static variables can hold the last emails, per pool, and they lost on recompile, but you can do some work. – Aristos Jul 30 '14 at 15:10
  • @Aristos Now you are making it more interesting. You are storing static data ? Which is first not recommended and it has Application level scope. What if another user is trying to send a similar email ? – fahadash Jul 30 '14 at 15:11
  • @Sifu it depends on your userbase, How many percent of your users are likely to try to "hack" their way into double-submitting your form ? If your system is vulnerable to the nerds who love to play with your security, then yes you should spend time perfecting it. Otherwise ask yourself, is it worth your time ? – fahadash Jul 30 '14 at 15:13
  • @Aristos I do have a database, I guess I could limit the ammount of email sent per user to 1 per 30 minutes for exemple. (Users need to be logined to access the post page) Thanks a lot! It is a good idea. – Sifu Jul 30 '14 at 15:14

1 Answers1

2

Here is a very simple example, where I use a static variable on page and avoid database.

the asp.net page is

<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" />/>

and the code behind.

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";
}

Some notes.

Community
  • 1
  • 1
Aristos
  • 66,005
  • 16
  • 114
  • 150
  • Very interesting! I already knew about the *honey pot trick* and the *captcha*. I do not have to protect myself from robots as a user has to register with a verified Email account to be able to send the email. I am trying to understand [dictionnaries](http://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx), but I can't seem to understand where it stores itself? (Because at every post-back, every variables are empty) – Sifu Jul 30 '14 at 15:38
  • @Sifu I have made an update to clear the old data. Look, I have place it as static, so its store himself on the global data of the asp.net pool. – Aristos Jul 30 '14 at 15:44
  • @Sifu Try it, its cool and its working :) I have made it and test it. – Aristos Jul 30 '14 at 15:46
  • I see! Thanks for your time writing this. I will use that to prevent multiple sendings. – Sifu Jul 30 '14 at 15:47