I'm auditing my website with w3af.
It says it found several issues on my site, but I doubt that's really the case.
One of the issues is:
The URL: http://localhost/en/login is vulnerable to cross site request forgery. It allows the attacker to exchange the method from POST to GET when sending data to the server.
I'm pretty sure it isn't vulnerable to a csrf attack since I have used crsf protection in my forms (field with token which gets checked).
So I am wondering what this message is about:
It allows the attacker to exchange the method from POST to GET when sending data to the server.
I don't care if an attacker would be able to switch from POST to GET or do I?
And if I do can you please explain why I do? How can it be exploited?
Coming from a point of view of no experience with w3af, I would assume that it has some pretty basic rules written into it and it checks those rules and reports back on them.
In this case it will probably check whether you have used $_REQUEST instead of $_POST or $_GET and then report an error if it finds it, regardless of the efforts you have made to secure this.
Everyone will code differently so getting software to understand the context of your code would be an amazing achievement and probably be beyond the intelligence of this one. This is not meant as an attack on the software, but to be honest if I came up with some program that could understand the context and intent of someone else's code, I wouldn't be giving it away on sourceforge :p
Does it matter? Maybe depending on how well you have secured the site (see Marc B's (+1) comment above).
-- EDIT --
By using $_REQUEST instead of specifying $_POST or $_GET you have left yourself open to an area of attack that is easily closed. Not only this but $_REQUEST also includes $_COOKIE. This has been covered here rather than me duplicating someone else's answer.
Related
I'm finishing up my first "real" PHP application and I am trying to make sure it is secure. I'm kind of afraid that since I'm not an "expert" PHP programmer that I might be missing something huge, so I would like to give you some information about my application and hopefully you can tell me whether or not that is the case. So here we go:
I'm using a CMS to handle user authentication, so I don't have to
worry about that.
After discovering PDO shortly after starting work
on my application, I ported all of my code over to using prepared
statements with PDO.
I am escaping all form and database data (even stuff I think is safe) which is being output with htmlentities().
My application does use a session variable and cookie variable, but the function of both is very unimportant.
I have designed my form processing functions in such a way that it doesn't matter if the form were somehow altered, or submitted from off-server (i.e. I always check the data submitted to ensure it's valid).
I have done my best to make all error messages and exception messages polite but very obscure.
I'm forcing pages with sensitive information (such as the login page) to be served over https.
When I first starting writing my application, I didn't know about prepared statements, which is kind of a huge deal. Have I missed anything else?
OWASP maintains a list of the Top 10 Most Critical Web Application Security Risks (warning, PDF download). This is from 2010, but I think it still applies, perhaps even moreso now.
Injection and XSS are the top two, but you should certainly be aware of the other 8. If you are using an existing CMS, many of these may already be considered, but the more popular the CMS the more you risk running into vulnerabilities because of black hats trying to find holes in it.
If you are not storing critical data like credit cards, order history, addresses, and even emails, then I wouldn't worry too much about your site being affected as long as you are taking the basic precautionary measures (and it sounds like you are).
If you are concerned about security issues, a good resource is the OWASP - Top 10 Application Security Risks
The most important thing to take care in web applications(specially PHPs') is Data Validation of all the inputs taken from the user which are further saved in your database.
For a secure application, all the transactions should be done on HTTPS. For a secure cookie management Secure and HTTPOnly cookie should be implemented.
Some more points I don't see mentioned yet. Most of these are not related to code - I am not sure if you only wished for things related to code, but I'll mention them anyway.
Backups (user data). should be self-evident
Version control. If you have a big bug, you want to have access to the previous version.
Audit trail, alarms and logging. If you do get into trouble, how will you find out? Are you able to track down what happened? if you know something is wrong but don't fully know what, are you able to diagnoze the issue?
Hosting. Where are you hosting? Do you have adequade bandwidth and monitoring? What happens if you get DOSed? Are you able to block out unwanted traffic?
Caching. Can you change it if needed?
There's always one thing left. Availability :) There are three aspects of security:
Confidentiality (Noone can read what they don't have access to)
Integrity (Noone can change any data what they should have to and you have to be able to detect if it happened even so)
Availability (The data, application whatever has to be available)
You pretty much did a nice job and took care of the first two (credentials, prepared statements, htmlentities...) but none of them will help against a DoS attack. You should be able to detect if someone slaps your site and ban the attackers ip from your server. Although this can be done in PHP (still much better to kick the attacker at the first line of php than let them initialize the framework, database connections etv.) it can be done mre effectively in lower layers (for example: nginx/apache, iptables, snort).
However what you're asking for that usually comes to the matter of risk management. In a real application you're not able to be prepared for all the possible attacks, edge cases etc. What you need to do is classify all the risks by the probability and the impact ( http://www.jiscinfonet.ac.uk/InfoKits/infokit-related-files/Resources/Images/risk-matrix ). With this you can focus on the most important (highest) risks first and probably you can completely ignore the lower bottom part.
SQL Injection and XSS are the most prominent Hacking methods.
You are covered from SQL Injections if you use prepared statements.
Also, if htmlentities() on everywhere you display HTML you should be safe.
What is the best solution to "form spoofing" besides filtering the inputs?
I understand the followings:
Referrer can be spoofed
Telnet can be used to fool the server
Client side filtering can be bypassed
i understand that i should avoid GET
I can use Captcha
How can i prevent somebody to post to my form processing scripts from anywhere?
If someone can manually post a form, they can do it automatically too. There's no way to stop that besides moderation. You can make it harder by using captcha's. But personally I hate captcha's, because they are just a solution made up by lazy moderators to make the users solve their problems.
Here is a way to use tokens.
http://shiflett.org/articles/cross-site-request-forgeries
Not much really. Every client-side check can be spoofed or bypassed. Some authentication method is best, either using HTTP Auth or a simple system you coded yourself with sessions.
I don't know what the best solution is necessarily, but you can use a session variable on the script that should have generated the form and check it in the script that the form POSTs to. You can md5 the variable contents and make it something somewhat random for increased security as well.
The real question is why do you want to prevent people from being able to post to your webpage from anywhere? Your webpage should be prepared to accept any input no matter where it comes from. There are measures you can take to reduce automatic posting such as tokens, but there is no way you can prevent it completely.
Instead of trying to prevent it, though, I would welcome it. Advertise your cross-site post API and profit.
Postel's law:
TCP implementations should follow a general principle of robustness: be conservative in what you do, be liberal in what you accept from others.
Set a hidden input on the form that's equal to the md5 value of a string made up of the session id + a secret "salt" string value. Then, when you process the form, you can get the session id, add the secret value, and compare the mp5 out of that to the value that was passed with the form.
There are tasks that can only be done by JavaScript.
My problem is that after doing the task from JavaScript, the JavaScript code has to send the variables to a PHP page and, from my knowledge, it can only be done by post, get, and cookie which means that a user can possibly fake the variable and submit it.
I want to make sure that the variables the PHP page receives is from the JavaScript page.
No luck so far. What is the solution?
You're right, this is certainly a problem.
Whitelisting/validating the input from the client could solve some of your problems, by making sure that the value is at least within a certain range of acceptable values.
What specifically is your use case that you're concerned about? Perhaps we could help you more if we knew more about your scenario.
We could help you better if you would describe your specific scenario and what kind of data input you need to avoid.
In general you should always try to validate data on the client (JavaScript) just to provide a better feedback to the user (like highlighting a required form field left blank). Consider this to be just as a courtesy for the user.
Regardless of that you should never trust the data coming from the browser and do all the security relevant validation on the server and don't care what kind of client software has been used to collect that data (being that your JavaScript code or some hard coded GET/POST data).
As the other answers have stated whitelisting is really the only thing you can do -- If someone is deliberately attacking your website there is no requirement that any content you get is valid.
No amount of client side validation or cookies works either as an attacker does not need to use a browser to do Bad Things.
You can generate an authenticity token when serving your page. Then check that the response contains the same authenticity token. A la rails.
I'm currently writing a web application which uses forms and PHP $_POST data (so far so standard! :)). However, (and this may be a noob query) I've just realised that, theoretically, if someone put together an HTML file on their computer with a fake form, put in the action as one of the scripts that are used on my site and populate this form with their own random data, couldn't they then submit this data into the form and cause problems?
I sanitise data etc so I'm not (too) worried about XSS or injection style attacks, I just don't want someone to be able to, for instance, add nonsense things to a shopping cart etc etc.
Now, I realise that for some of the scripts I can write in protection such as only allowing things into a shopping cart that can be found in the database, but there may be certain situations where it wouldn't be possible to predict all cases.
So, my question is - is there a reliable way of making sure that my php scripts can only be called by Forms hosted on my site? Perhaps some Http Referrer check in the scripts themselves, but I've heard this can be unreliable, or maybe some htaccess voodoo? It seems like too large a security hole (especially for things like customer reviews or any customer input) to just leave open. Any ideas would be very much appreciated. :)
Thanks again!
http://en.wikipedia.org/wiki/Cross-site_request_forgery
http://www.codewalkers.com/c/a/Miscellaneous/Stopping-CSRF-Attacks-in-Your-PHP-Applications/
http://www.owasp.org/index.php/PHP_CSRF_Guard
There exists a simple rule: Never trust user input.
All user input, no matter what the case, must be verified by the server. Forged POST requests are the standard way to perform SQL injection attacks or other similar attacks. You can't trust the referrer header, because that can be forged too. Any data in the request can be forged. There is no way to make sure the data has been submitted from a secure source, like your own form, because any and all possible checks require data submitted by the user, which can be forged.
The one and only way to defend yourself is to sanitize all user input. Only accept values that are acceptable. If a value, like an ID refers to a database entity, make sure it exists. Never insert unvalidated user input into queries, etc. The list just goes on.
While it takes experience and recognize all the different cases, here are the most common cases that you should try to watch out for:
Never insert raw user input into queries. Either escape them using functions such as mysql_real_escape_string() or, better yet, use prepared queries through API like PDO. Using raw user input in queries can lead to SQL injections.
Never output user inputted data directly to the browser. Always pass it through functions like htmlentities(). Even if the data comes from the database, you shouldn't trust it, as the original source for all data is generally from the user. Outputting data carelessly to the user can lead to XSS attacks.
If any user submitted data must belong to a limited set of values, make sure it does. For example, make sure that any ID submitted by the user exists in the database. If the user must select value from a drop down list, make sure the selected value is one of the possible choices.
Any and all input validation, such as allowed letters in usernames, must be done on the server side. Any form validation on the client, such as javascript checks, are merely for the convenience of the user. They do not provide any data security to you.
Take a look # nettuts tutorial in the topic.
Just updating my answer with a previously accepted answer also in the topic.
The answer to your question is short and unambiguous:
is there a reliable way of making sure that my php scripts can only be called by Forms hosted on my site?
Of course not.
In fact, NO scripts being called by forms hosted on your site. All scripts being called by forms hosted in client's browser.
Knowing that will help to understand the matter.
it wouldn't be possible to predict all cases.
Contrary, it would.
All good sites doing that.
There is nothing hard it that though.
There are limited number of parameters each form contains. And you just have to check every parameter - that's all.
As you have said ensuring that products exist in the database is a good start. If you take address information with a zip or post code make sure it's valid for the city that is provided. Make countries and cities a drop down and check that the city is valid for the country provided.
If you take email addresses make sure that they are valid email address and maybe send a confirmation email with a link before the transaction is authorised. Same for phone numbers (confirmation code in a text), although validating a phone number may be hard.
Never store credit card or payment details if it can be avoided at all (I'm inclined to believe that there are very few situations where it is needed to store details).
Basically the rule is make sure that all inputs are what you are expecting them to be. You're not going to catch everything (names and addresses will have to accept virtually any character) but that should get most of them.
I don't think that there is any way of completely ensuring that it is your form that they are coming from. HTTP Referrer and perhaps hidden fields in your form may help but they are not reliable. All you can do is validate everything as strictly as possible.
I dont see the problem as long as you trust your way of sanitizing data...and you say you sanitize it.
You do know about http://php.net/manual/en/function.strip-tags.php , http://www.php.net/manual/en/function.htmlentities.php and http://www.php.net/manual/en/filter.examples.validation.php
right?
What ways are there for detecting exploits in PHP/MySQL web applications (checking for certain characters or pieces of codes in the GET, POST, COOKIE arrays / using a library with a database that has all the patterns for common exploits, if any exist?) and how should I proceed when one is detected?
For example, if someone tried to find a SQL injection in my PHP/MySQL web application using the GET request method, should I store the action performed by the user in the database, have the application send me an e-mail, IP ban the user and display him/her a message "Sorry, but we have detected a harmful action from your account that will be reviewed. Your account has been disabled and certain features may be disabled from your IP address. If this is a mistake, please e-mail us with all the details."
Thanks.
Three things come to mind:
defensive coding, sanitize all input, prepare sql statements and use Suhosin
increase security of your site by breaking into it with a vulnerability scanner
log hacking attemtps with an Intrusion Detection System
If you feel a full fledged IDS is too much, try PHP IDS, as it does pretty much what you are asking for out of the box. Note that detecting intrusions at the PHP level might already be too late though to prevent an attack.
In case of a successful intrusion, I guess your best bet is taking the server offline and see what damage was done. You might have to consider hiring someone to do a forensic analysis of the machine in case you need to collect legally usable evidence.
If you feel you need to react to unsuccessful intrusion attempts and got the malicious user's IP, find out the ISP and inform him with as much details of the intrusion attempt as possible. Most ISPs have an abuse contact for these cases.
Your question is twofold and I'll answer the second part.
Log everything but do not ban or display any message. It will be embarrassing in case of a false positive. As a general rule, try to build an application that can deal with any sort of user input without a problem.
just use strip_tags() on all $_REQUEST and $_COOKIE vars to take care of code showing up in these vars, as for SQL you would have to maybe write up a query-like regex or something, but this shouldnt be an issue as you should always mysql_real_escape_string($str) all variables in your queries. try something like this though.
function look_for_code_and_mail_admin($str) {
$allowed_tags = "<a>,<br>,<p>";
if($str != strip_tags($str, $allowed_tags)) {
$send_email_to = "some#bodys.email";
$subject = "some subject";
$body = "email body";
mail($send_email_to,$subject,$body);
}
return($str);
}
Um, I can't remember the last time I've seen a site that tries to log SQL injection attacks that I wasn't able to penetrate..
You don't need to worry about weather someone is attacking the site, as it is subjective at best as to weather something is an attack or not. What if the site base64 encodes some values and decodes them before it uses it? Your IDS is not going to catch that. What if a user wants to post a snippet of code, it gets detected as an exploit because it contains SQL? This is such a waste of time... If you really need to know if someone's attacking you, just install some IDS on a seperate machine with readonly access to the incoming traffic.. I say seperate machine, because many IDS are vulnerable themselves, and will only make the situation worse.
Use standard secure programming methodologies, use paramaterized SQL queries or an ORM.
Seems like too much work with the email bit and everything to me. Aside from that, I like to run around on sites I commonly use and try to find injectable points so I can warn the administrator about it. Would you IP ban me for that?
I suggest hunting down the exploitable parts yourself and sanitizing where necessary. Acunetix has a very very good program for that. If you don't feel like shelling out the giant price for Acunetix, there are some very good firefox addons called XSS Me and SQL Inject me you might want to look into.