/    Sign up×
Community /Pin to ProfileBookmark

Securing PHP form: Is this enough?

I have created a php contact form. Tried to keep it lightweight. I have a separate html contact page and then a separate php form that runs the script. So here it is:-

1) I have 4 required fields (name, email, phone, message) & 1 hidden honeypot field for spam prevention
2) All the 4 required fields have on-page jQuery validation for the user. The form won’t submit if the fields are not filled in.
3) I have if (empty code in the php to ensure that the email will not be sent if the honeypot field is filled.
3) I have a !preg match function in the php script to prevent email injection via the email field.

What else do I really need to add to be secure or is this enough for a simple form? I know some people go to all sorts of lengths to try to prevent abuse and some of the scripts I’ve seen are huge. I’m trying to keep things lightweight and simple as possible. Any advice?

to post a comment
PHP

9 Comments(s)

Copy linkTweet thisAlerts:
@ginerjmJul 03.2015 — Item 3 seems backwards. Also there are php filter functions to help you validate an email.
Copy linkTweet thisAlerts:
@Wild_ThingauthorJul 03.2015 — Item 3 basically tells the form to send if the honeypot field is empty. That's not backward that's the intended behaviour.
Copy linkTweet thisAlerts:
@NogDogJul 03.2015 — While item #2 is a nice UI feature, you still need to validate that the fields are filled in on the PHP side, since JavaScript validation is easily bypassed by malicious users -- or simply someone who feels inclined to browse with JavaScript disabled.

Also, be careful with email validation regexes -- I've seen way to many of them out there that will reject addresses which are, in fact, valid formats. (I tend to assume that the user knows his/her email address -- besides which they can enter a non-existent or incorrect email address that matches the pattern, so not a whole lot is gained by overly-aggressive pattern-checking.)

Lastly, you might want to add some CSRF protection, typically by generating a random token stored in $_SESSION and put in a type=hidden field, which must match the session value before the form will be processed.
Copy linkTweet thisAlerts:
@Wild_ThingauthorJul 03.2015 — While item #2 is a nice UI feature, you still need to validate that the fields are filled in on the PHP side, since JavaScript validation is easily bypassed by malicious users -- or simply someone who feels inclined to browse with JavaScript disabled.[/QUOTE]
Agreed. The jQuery though is very user-friendly and gives instant on-screen validation to the user. But yes I recognise that server-side validation is essential and as you see from my question I have this in place...


Also, be careful with email validation regexes -- [/QUOTE]

I'm not using regexes to validate email. My code basically ensures that all 'required' fields are filled. But it doesn't go as far as to set up rules for what can be put in the field eg Name must be (A-Z) or telephone (0-9). Is this a big problem that I've not defined what the user can specifically put in the field. The only rule I have created is a code to stop email injection in the email field with BCC etc
Copy linkTweet thisAlerts:
@NogDogJul 03.2015 — I may have misinterpreted what you meant about the email validation.

One of the simplest ways to protect against email header injection is to simply not allow (or strip out) carriage return and newline characters. If you also want to validate the format, I might instead just use PHP's filter_var() function with the FILTER_VALIDATE_EMAIL filter, and let it take care of verifying both format and safety (since newlines and such would not be valid in an email address).
Copy linkTweet thisAlerts:
@Wild_ThingauthorJul 03.2015 — @NogDog yes agreed..again! You explain it well. What I have done is now just changed the email field validation within the PHP code as you suggested. It now reads as follows:-

[CODE]!empty($_POST['email']) && filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)
? $success['email'] = $_POST['email']
: $errors[] = 'email';
$body .= !empty($success['email'])
? 'E-Mail: ' . $success['email'] . ' n'
: '';[/CODE]


How does that look??
Copy linkTweet thisAlerts:
@ginerjmJul 03.2015 — I see you took my advice on using the php function to validate the email. (And nogdog's)

Getting back to your 'honeypot'. Not sure how you define a 'honeypot' but the concept of using a hidden field is usually executed by having a hidden field with a value in it that your php script (that sent the form) placed there and that you script then looks for when the form is submitted. Your response to my "it's backwards' statement makes no sense. And empty form is Good in your scheme? I may be wrong here but the manual clearly states that an empty() check will return true if the field is truly empty (a false value) or IF IT DOESN'T EXIST. Well, if the form is spoofed there won't be a honeypot so your empty test will give you a true value which I'm sure you don't want.
Copy linkTweet thisAlerts:
@NogDogJul 03.2015 — I think the "honeypot" idea is that it looks like a field to be entered to a bot script, but since it's hidden via CSS, a normal "human" user would never fill it in. I suppose its effectiveness will depend on how smart the bot is, and you have to weigh it against the possibility that some legitimate users might still see the field (maybe a text-to-speach system for the vision-impaired?).
Copy linkTweet thisAlerts:
@Wild_ThingauthorJul 04.2015 — I think the "honeypot" idea is that it looks like a field to be entered to a bot script, but since it's hidden via CSS, a normal "human" user would never fill it in. [/QUOTE]

That's exactly correct.
×

Success!

Help @Wild_Thing spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.24,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @AriseFacilitySolutions09,
tipped: article
amount: 1000 SATS,

tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,
)...