PHP CSRF Form token + validation advice - php

I've got a submission form, with 9 fields, 6 of which require validation, including a upload field with file size and file type validation.
Generating a random token, to prevent CSRF is working, but what is the correct way to validate when using a token?
If I do the validation within the same file, the token is regenerated with the validation reload. (can this be prevented? I've tried isset() but still regenerates.) However using the same file prevents the users Name and Email from being stored in a session.
Is it best to do the validation within a separate file, which then redirects back to the form with basic variables in the URL for each error, i.e. http://www.example.com/form?n=1
Using a separate file would also mean storing the form data within session, so the form can be repopulated if errors exist on the redirect.
Any help gratefully received.

From experience, CodeIgntier does great CSRF implementation, among other security mesures. I would suggest that you go over their code to gain a good understanding of the whole process. Also see this.

Related

Prevent form submission from other pages

I have created this function:
function blacklisted_ip() {
$('form').remove();
$('.wrapper').removeClass('form-success');
$(".login_text").html("Your IP has been blacklisted");
}
that removes a HTML form - I remove the form to stop users with a blacklisted IP logging in.
I have a php script at the top of the same page that processes the login when the form is posted.
Is there also a way i can stop other pages posting to this page?
the php starts like this:
if($_POST) {
}
I thought about adding a hidden field with a value in but then thought someone will be able to view the source and just copy it?
Best way to do this is using CSRF tokens. If you're suing any frameworks the they're already implemented out of the box, if not and if you want to implement it on your own you can do it.
CSRF stands for Cross-Site Request Forgery, which is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user’s web browser to perform an unwanted action on a trusted site for which the user is currently authenticated.
Reference: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
Solution to prevent this is to have a unique CSRF tokens for each users for each form. When ever user opens the page and form is loaded you assign a token/key to that (page+form) and save that in session with expairy of your choice.
Add this token along with the form as hidden field and post that along with other datas, now when you process the form compare the token received from client side along with your sessions's token. If they match they're authenticated and if not don't process the form.
You can use any method to generate the CSRF tokens, in your case they would be just unique keys for each page+form.

Ensure that PHP form process file is only used with specific web form page?

I am a little new to PHP, and I have gotten in the habit of creating a specific file that handles all the form processing.
For example, I have one PHP file that displays the actual form, let's called it "registration.php" for example, and it specifies as its action "registration-process.php". A user fills out the registration form on registration.php, hits submit, and the data is POSTed to registration-process.php because it was specified as the action file by the form.
Now my question is this: Can't someone who knows what they are doing POST data to registration-process.php without going through registration.php? This would have the potential to lead unexpected consequences.
Is there any way to ensure that registration-process.php will ONLY accept POSTed data from registration.php? Like maybe a hidden field with a value that gets encrypted via some PHP code, and that value gets checked by the registration-process.php file? I wouldn't know how to do that, however, or if that's even the best solution.
Yes, using a hidden "security token" field is a common way to verify a forms integriy. Many public forums are using this method.
Try Google for php form security token or check out this site:
http://css-tricks.com/serious-form-security/
Can you only accept POST data from one location, probably. It is worth it, probably not.
As long as you are validating your form fields correctly (make sure what you're getting is within the realm of what you're expecting) there won't be any negative consequences of leaving it so anything can POST to it.
Also, technically you can send POST data to any file on the web, it just depends on what the file does with it whether or not it means anything.
Also, what Mario Werner is talking about is CSRF tokens. That won't stop other things from posting to your site, it just adds a level of security that makes sure the request came from the right place. For a detailed explanation, you can read this: http://en.wikipedia.org/wiki/Cross-site_request_forgery

How can I protect a form processor script file?

I have set up a rather complicated HTML form that uses the JQuery Validate plugin with several required fields and various rules. Form is working great. It POSTs to a separate PHP processor file that does a number of things such as send a couple of emails and eventually sends the user to Paypal. (It is a club membership application.) It appears that it only took about a week for some type of "bot" to find the processor file and start running it directly over and over. About 500 emails & apps were generated before I caught it and stopped it by renaming the files temporarily. At the time it was happening I wasn't quite sure exactly what was going on, but after evaluating it for most of the day I came to realize that it couldn't be as a result of the main form being executed, but by just running the processor file directly.
So...my question is this: How can I keep this from happening? There must be some type of coding to include that will ensure that the processor can't run unless it is really coming from the real HTML form...or is there a better way? I followed all of the "examples" on the 'Net in regards to forms and POSTing but nowhere did I see anything that relates to this type of problem.
Generally this can be reduced by adding a CSRF token to the form.
Set a random sha/md5 value to your session, and set that value in the form also as a hidden input, upon a legit user sending the form that value will be passed along too, validate and check the passed value with the one in session. if all is good process.
If its a bot, the bot would need to parse the form for the CSRF token first. Or you could step up and make that security key an image and make the user type it (captcha).
How to properly add CSRF token using PHP
Its something you should also add to your login forms ect, else your have bots brute forcing there way in.
Maybe you could add a $_SESSION[] global variable on the form page. Then check it on your processing page and unset it after execution. Sounds like the simplest way to me, but you should hear out what others suggest. You can fin documentation on $_SESSION[] variables here PHP $_SESSION
Add a token to the form when generating the page, and save it into the session.
When you got the post data, check the token with the one in the session.
And you probably want to use CAPTCHA code to protect yourself from the bots.

How much of an html form can be altered without triggering CSRF protection?

I implemented CSRF protection by including a token with PHP into a hidden input for every form. Each token can only be used once, of course.
However, there are tools, such as any web developer tools, which allow inputs to be changed. For example, I can change on-page input forms: I can make disabled checkboxes enabled, and I can change input boxes to textarea boxes without reloading the page or anything like that. CSRF wouldn't catch such changes.
So, how much of a form do I need to validate to stay safe? Do I need to validate every single input to make sure it wasn't altered, including selects, checkboxes, hidden inputs, etc? Surely it can't be safe to assume that these haven't been altered?
You need to validate (on the server side) everything that needs to be validated. What exactly needs to be validated depends on many factors and personal choices. Some of it may be for safety, but only a bare minimum is needed for that in many cases. For the most part validation is to improve or create user experience.
For example you can check to see whether they have entered a valid email address. If they haven't, you can give them a message. If you don't do that nothing bad will happen to your application, but the user won't be able to receive email from you.
There is also an important distinction between validation and sanitation. Sanitation is done for security (e.g. to prevent injection). Validation is done to make sure that input meets requirements to work correctly with your application although incorrect input may be benign. It's also possible for sanitized malicious input to be valid.
All input must be sanitized. No input needs to be validated, so it's really up to you.
CSRF protection has nothing to do with validation. All it does is prevent a user from making a request using your form from an external source because the only way to generate and see the token is to make a request to your site first.
What we are trying to do using CSRF is to ensure that the request IS coming from a reliable source. For e.g, your case what you need to do is ensure that the value in the hidden field is sane. And it can be sane (provided that your token is strong enough) only if it is the same as the one that was provided while the form was rendered by the server.
Now whether fields in the form changed or not, is just your application logic. It does not have anything to do with csrf. If the token is sane, then it came from the right source. Now, if it was the same person who entered values in the form for e.g. is not within the scope of csrf.
I think you are getting the wrong end of the stick here. The token is not a hash of the form when it was sent.
The way this works is to store your unique token in a hidden field on the form and into the session when you server the original page.
When you get the page POSTed/GETed back from your user you check that the token on the page is the same as the token previously stored in the session.
Changing fields must still be allowed or your user will not be able to enter any data on the form. You are just checking that you got the same form back that you sent, because the token is the same, rather than one from somewhere else, i.e. its not a cross site request forgery.
You still have to validate all the fields and do any data preparing before storing it in a database.
Reading1
Reading2

protection against CSRF without hidden input in all forms

I wonder if I could put the crsf token in <head>, on a meta tag or something, and then access it on my server. It would really simplify the process and make it more transparent. I just don't know how. I was really hoping to do this without javascript involved.
I think rails implements something like that...with etags maybe?
There are many methods listed on the CSRF prevention cheat sheet. One that doesn't require a hidden field on every form, is to check the referer. Keep in mind the lack of the referer should be considered a CSRF attack and may cause problems with some privacy browser addons (which is very uncommon).
The fundamental purpose of a CSRF token is that it is delivered back to the server with each form submission. You deliver the unique token to a page, and when the form on that page is submitted the token comes back with it.
If you don't include the token on the form (or use JavaScript to programmatically add a token to the form that's currently elsewhere on the page) it will not be sent back to the server.
Perhaps the better question is: what is it you're really trying to accomplish? In other words, why would you not want to include a CSRF token within the form? What's the disadvantage you'd like to overcome in your scenario?

Categories