homepage Welcome to WebmasterWorld Guest from
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member

Home / Forums Index / Code, Content, and Presentation / PHP Server Side Scripting
Forum Library, Charter, Moderators: coopster & jatar k

PHP Server Side Scripting Forum

Opinions on anti-spam solution
What are the weaknesses of my solution?

10+ Year Member

Msg#: 3166575 posted 1:29 am on Nov 24, 2006 (gmt 0)

I have recently implemented a simple php contact form for a client who had suffered header injection spam with the previous form. My solution is holding up well for now but I would like opinions from others experiences.

Rather than search for \r\n or to: cc: bcc: or content-type or . . . I decided to validate the single line entries and test the message contents to ensure that injection type data was just sent as a message and didn't create any additional messages.

The form has only four fields: name,email,subject,comments. What I did was to use regex to validate the first three:

Name ^([A-Z '-]+)$
Contains alphas, dashes, spaces and apostrophe for O'Malley. Names longer that 50 characters are truncated and have ... added

Subject ^([A-Z0-9 '-:\!\?]+)$
Similar to name with the addition of some punctuation. Long subjects are truncated in the same way as long names.

Note that neither of these fields can contain @ signs, CRLF characters or the % that the hex equivalents would contain.

This only allows one email address that I use as a reply-to but not as a from. No surprises created by replying to multiple email addresses. This will not allow a valid email address with a .museum domain but the client doesn't expect these. They would be allowed if I used (2,6) instead. At present, I am also truncating email addresses longer than 50 characters - I find it hard to imagine that a regular human user typing an email address into a box on a form could have an email address longer than 20 - 30 characters at the most.

For the actual message, I want to allow anything and preserve the crlf for formatting. I found that I could create an extra header if I a \r\nbcc:email@domain.com at the very end of the message. Then, when I added my \r\n to send the message, an email was sent to the injected address. To prevent this from happening, I just added a string at the end of the message. In my case, I added the IP address originating the form message. But pretty well any "end of message" string would work, it seems to me.

Magic_quotes are on and I strip_slashes before sending the data - also strip_tags, keeping \n (but not \r) for only the message and then replacing the \n with <br>\r\n to keep paragraph formatting. This seems to sometimes add extra paragraph spacing so if anyone has a comment about this I'd appreciate it.

I created test data using the types of header injection data described at


but using my own email addresses. I checked the headers of the email that arrived at the recipient and also checked to see whether any email arrived at my additional email addresses.

I know that they can be spoofed but I also check for valid referrers using $_SERVER['HTTP_REFERER'] and an actual (i.e. not blank) browser using $_SERVER['HTTP_USER_AGENT'] - should I bother or do most spammers spoof these?

I check that $_SERVER['REQUEST_METHOD'] is 'post' because I saw it suggested somewhere but I don't really understand the reasoning behind it so if anyone can enlighten me I would appreciate it.

To hopefully prevent flooding, the system uses a session variable to prevent another message being sent after the first one. If the user closes the browser and re-opens it, they can send a second message.

I calculated that most normal users would take about 30 seconds at the very least to type an entry in every field of the form and a couple of lines in the message so I added a time delay. I record a timestamp at the start of the session and calulate the elapsed time just before sending the message. If the elapsed time is less than 30 sec, I just sleep until the 30 sec is up. Actually, I had to sleep for 2 sec, output a blank and then sleep for 2 sec in a while loop or the browser created a time out.

If anyone wants to or is willing to test my form, I will give you a link to my test version of it if you PM me.

Is there anything different that people think I should be doing? Or? This is working right now but I am a relative novice at php and I am hoping that others who know more will have some comments on what I have come up with.

Thanks in advance for any/all comments.



WebmasterWorld Senior Member dreamcatcher us a WebmasterWorld Top Contributor of All Time 10+ Year Member

Msg#: 3166575 posted 9:16 am on Nov 26, 2006 (gmt 0)


Try this [webmasterworld.com] related thread.


Global Options:
 top home search open messages active posts  

Home / Forums Index / Code, Content, and Presentation / PHP Server Side Scripting
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved