I have tried two approaches:
-- Using form_open : With this approach, I am able to add a field with CSRF Token in request header as well as in cookies. But the same CSRF Token is generated every time and hence not able to prevent the attack.
Also I need to know apart from adding Token on client-side, is there any need to check it at server-side or it is automatically done.
-- Using hidden input field with custom form tags : With this, I added a random token as the input field, still not able to avoid the attack.
For second approach, I need to know the changes we need to do in Security.php file and for this also if we have to do any server-side check or not.
The first approach is advised mainly because the CI code is well-tested, tried-and-true code. I assume the second method is something you intend to write yourself. If that's the case you are reinventing the wheel without good cause.
Using the CI code it is important to understand that the hash value of the token will not change unless you use the following in config.php
$config['csrf_regenerate'] = TRUE;
The other thing you need to know is that a new hash will be generated only when a POST request is made to the server. That's fine because the need for CSRF protection is only relevant for POST requests.
When making multiple GET requests, i.e. loading a <form> a number of times in succession, you will likely see the same hash value each time. But if you submit the form and then reload it you will see a new hash value.
Finally, you should know that the CSRF values are only checked for POST requests and are not checked for GET requests.
The hash value will be removed from $_POST after it is successfully validated.
All of the above is happens automatically if you use the $config setting shown in combination with form_open().
Related
Is it safe to use $_POST for button action ?
for ex.
<button name="submit">Table A</button>
php (what my code here does is, if i click the button(Table A) the table A will appear then, in default is not viewable.)
if(isset($_POST['submit'])) {
<table>
code....
</table>
}
FOR MY QUESTION: is it safe ? to the attacker ? like xss, sql injection, or something ? I want an advice, to have more safer website. (or atleast safer from attackers)
It is safe provided you don't echo the output or use it unescaped within a SQL statement. Also your code should really be...
if(isset($_POST['submit'])) {
...
}
to avoid errors if it isn't set
Developer has always to sanitize and to validate the input he's getting from the request.
Depending on the purposes - you need either to enforce the sanitation or to make less cleaning (for example for DB you need to clean it up/escape additionally, for HTML output to make XSS protection, etc.)
You may read up on:
How to sanitize the input (POST/GET variables, referral, cookies, user agent, and other headers)
Cross-Site Request Forgery (CSRF) prevention;
additionally you may want to use Captcha or other protection from automatic submits, etc.
For your specific purposes, in the question itself - you are not using the value of $_POST['submit'] in any way, except checking of presence, so no additional validation is needed, it's fine like that.
Short answer
NO
POST variables are not 'safe' on their own.
Long Answer:
There are many issues around authenticating POSTed variables on your PHP script. The most well known is Cross Site Request Forgeries whereby the value is sent to your page but you have no idea where the value came from, or who sent it.
To counter this you need to set up single use unique keys to send and receive, typically using PHP SESSIONS or similar concepts that can not be touched by the end user.
The second issue is that you should never ever ever trust the contents of a POSTed variable. you need to fully escape the variable as well as ensuring that the variable is given absolutely minimum access to your code, so if it is a compromised value, it is hopefully cleaned and/or it can not harm your script.
Your Code:
Looking at your question in detail you suffer from CSRF (point 1, above) in that your PHP code has no idea if the submitted button came from the page your button exists on and therefore the PHP has no idea if the browser should see the contents of "Table A". (If everyone can see it, why hide it in the first place?)
There is also the factor your code could be used by a nefarious party to send many, many POSTed submits to the script, over a short space of time (100,000 over 2 seconds) causing a DOS attack, again due to there being no validation of where the POST came from and its implied authenticity.
Further points: You need to clarify what you deem as "safe", it is a very relative term.
You can use the button with POST. But make sure, you have validated the referrer URL of the action. Because someone may try to copy your form and submit in loop. This will down your site.
So you should check the referrer URL matches with your site URL.
Also always use form token to validate the form (Like captcha)
This is mostly a generic question, but I am specifically working with ZF2. I'd like to understand exactly how the CSRF token works and what determines how long a TTL (timeout) I should have on it.
I understand that it is generating a unique hash for each form that is rendered and checking that hash on submission of the form, but what does it check it against, is it keeping a copy of the hash on the server side as well? Is it single use? I'm guessing not since I can re-submit the same form multiple times (i.e. hit refresh on the page that results from the form post). But, it must be specific to that form and my current session, right?
Why does it need to time-out? Currently, I somewhat frequently have pages where I submit, or re-submit, the form after 5 mins (the default ZF2 CSRF timeout) and I get the CSRF error message. This is an annoyance for legitimate user interaction. Should I increase or remove the timeout? What's the security trade off?
I'm hoping by having a better understanding of the mechanics of ZF2's CSRF system I'll be better informed for decisions like this. Also, what are your recommended CSRF configuration options?
What is the best way to protect again CSRF attacks in PHP.
It has been recommend to use form tokens, so basically generate a random value and store it in a hidden field. Then also store this random value in the users session.
Finally in the form action, make sure the session and form token match.
if($_SESSION['token'] !== $_POST['token']) {
die("bad... spanking...");
}
Is there a better/easier way, as this requires a lot of code modification in my application (lots of forms and actions).
No. To protect against CSRF, you need to make sure you only trust credentials that are automatically appended to requests (like cookies) when you have reason to believe that the user actually submitted your form. The only way to do that is to have the form carry some kind of secret that the server uses to authorize processing.
If you use a framework or library to compose your form it might help by generating the random number, setting the cookie or session property, and adding the hidden input to your form but those three steps do need to happen.
Is this enough for CSRF protection:
A random string is generated, $_SESSION['hash'] stores it
A hidden value (in $_POST['thing']) in a form contains the random string
When the form is submitted, it checks if $_SESSION['hash'] equals $_POST['thing'], and continues if they match
One of my site's users keeps telling me that my site is vulnerable, but I can't tell if he's just trolling me. Is there anything else that I can do?
What I think you are missing is limiting token to small window of time.
You should have a look at Chris's CRSF-article. A quick summary:
a CSRF attack must include a valid token (anti-CSRF token) in order to perfectly mimic the form submission.
The validity of the token can also be limited to a small window of time, such as five minutes
If you use a token in all of your forms as I have suggested, you can eliminate CSRF from your list of concerns. While no safeguard can be considered absolute (an attacker can theoretically guess a valid token), this approach mitigates the majority of the risk. Until next month, be safe.
If it's unique to every user, then it should be enough. Even if it's the same for duration of user session, it's still OK, but I would suggest to re-generate it periodically.
Also you may want to use different tokens per each form. For example, if you have login form and comments form, it's better to use different tokens for them, but it's not 100% necessary.
Why do you assume that just because someone says your site is vulnerable, it has to do with CSRF attach? They are so many other possible vulnerabilities.
Maybe your web server outdated and vulnerable, maybe the php version is not the most recent one. Maybe the user was able to login to your server via ssh or telnet. Maybe the user was able to guess admin password.
Maybe to let people login by cookie and store login credentials in cookies.
There are just too many things other than CSRF that could be exploited. There is also a possibility that the user is wrong or does not know that he is talking about or maybe he just wants to make your nervous.
Each time they load the page, it changes IF it's not already set.
Well there is your problem. Once a token is retrieved all the actions can be easily performed further one. I usually implement the token to be valid for one single request and afterwards regenerate it.
from : http://en.wikipedia.org/wiki/Cross-site_request_forgery
you can additional decrease time of life of cookie
check the HTTP Referer header
and captcha - but not every user like it
however your acion with secret key is still better than nothing...
I don't run a mission critical web site so I'm not looking for an industrial strength solution. However I would like to protect against basic attacks such as someone mocking up a false page on the hard disk and attempting to gain unauthorized access. Are there any standard techniques to ensure that form submission is only accepted from legitimate uses?
A few techniques come close:
Produce a form key for every form. The key would relate to a database record, and something else unique about the page view (the userID, a cookie, etc.). A form cannot be posted if the form key does not match for that user/cookie. The key is used only once, preventing an automated tool from posting again using a stolen key (for that user).
The form key can also be a shared-secret hash: the PHP generating the form can hash the cookie and userID, for example, something you can verify when the form is posted.
You can add a captcha, requiring a user to verify.
You can also limit the number of posts from that user/cookie (throttling), which can prevent certain forms of automated abuse.
You can't guarantee that the form isn't posted from disk, but you can limit how easily it is automated.
You can't. There's no reliable way to distinguish between an HTTP request generated from a user on your page, or a malicious user with their own web-page.
Just use a proper password authentication approach, and no-one will be able to break anything unless they know the password (regardless of where the HTTP requests are coming from). Once you have reliable server-side authentication, you don't need to waste time jumping through non-robust hoops worrying about this scenario.
You should not create a login-system yourself because it is difficult to get it right(security). You should NOT store the passwords(in any form whatsoever) of your users on your site(dangerous) => Take for example lifehacker.com which got compromised(my account too :(). You should use something like lightopenid(as stackoverflow also uses openid) for your authentication.
The remaining forms you have on your site should have the following protection(at least):
CSRF protection: This link explains thorougly what CSRF is and even more important how to protect against CSRF
Use http-only cookies: http-only sessions, http-only cookies
Protect against XSS using filter.
Use PDO prepared statement to protect youself against SQL-injection
i also recommend:
Save the IP of the computer that sends the form (to block it from the server if it.s annoying)
Use CAPTCHA when required, to avoid robots...
Send users to another page when the info is loaded, so the POST data won't be retrieved when you refresh the page.
Proper validation of form data is important to protect your form from hackers and spammers!
Strip unnecessary characters (extra space, tab, newline) from the
user input data (with the PHP trim() function)
Remove backslashes () from the user input data (with the PHP
stripslashes() function)
for more detail, you can refer to Form Validation