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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Best way to prevent SQL injection in PHP?
I am creating a news site and I have written down a list of things need for achieving security.
User + Site interaction
sanitize all POST/GET functions with html-entities & mysql_real_escape_string
if site is about to be online, TURN OFF, error reporting or customize it
I don't use cookies, only sessions (Because sessions are less vulnerable)
turn off directory listing
make robot.txt to prevent indexing unwanted files
For passwords, use salt + Md5
only make ADMIN site accessible from one PC and one browser by getting ip, and browse info, otherwise throw in 404 Error.
I have implemented all those in my site. I know most of you will say use PDO / Msqli to sanitize, but I am a beginner in PHP and it is difficult for me to learn PDO/Mysqli or OOP
So, anything other you can provide will be awesome.
thanks.
--> sanitize all POST/GET functions with html-entities & mysql_real_escape_string
Why html-entities? You only need them to display information in html format. Don't use it while receiving and storing info.
Also: mysql_real_escape_string only works for text. If you want to receive, say, an integer, do this:
$myInt = (int)$_POST["whatever"];
--> if site is about to be online, TURN OFF, error reporting or customize it
Yes, use a log file to store them and look into it an a regular basis.
--> I don't use cookies, only sessions (Because sessions are less vulnerable)
How do you relay the PHPSESSID without cookies? Not in url I hope. I guess you meant: I use only cookies to store PHPSESSID.
A security improvement: Make a new sessionid for each request.
--> turn off directory listing
Good.
--> make robot.txt to prevent indexing unwanted files
OK, but sensitive files shouldn't be in the webroot anyway (eg, db credentials)
--> For passwords, use salt + Md5
md5 is weak. You might want to look into other ways for one-way encryption.
--> only make ADMIN site accessible from one PC and one browser by getting ip, and browse info, otherwise throw in 404 Error.
That is a good idea.
There is a lot more to add. Most has to do with your logic.
For example: If you have users with a userid, and postings with a postingid. You want to store postings in tblpostings, also storing the userid, so you know who wrote it.
Now, if you enable deletions of posts you must somehow check that the one who deletes the posting is also the owner.
These kind of things are hard to fit in simple general rules. Just pay attention when you write code. :-)
I'd be careful of robots.txt files as although they're supposed to stop robots from indexing certain bits, they also tell people bits of your site you don't want them to look at.
Not strictly, PHP and XSS, but if the server is on linux, disable root ssh account and have another which you use. Have database specific users, so if one is compromised, other databases aren't.
"For passwords, use salt + Md5"
Better than clear text, but the best currently known algorithm is bcrypt, and described here:
How do you use bcrypt for hashing passwords in PHP?
SQLInjection
Stop using mysql_real_escape_string and start using prepared statements/parameterized queries. Learn PDO now, it's not that hard, and will help you get things right from the beginning.
XSS
Look into contextual escaping on output. See the OWASP XSS prevention cheat sheets.
Issue a new session on login. Dont leak that session over http. Use https for logged in users and set the secure and httpOnly flags on the session cookie.
Use bcrypt, scrypt or pbkdf2 for password hashing.
As other said, dont put sensitive files on the server unprotected. Robots.txt is a good place to start for hackers.
I've read up on SQL Injection, XSS and other security issues and am trying to figure out what to use to safeguard the company's site.
We are about to deploy a simple 'User feedback' form with a textarea so users can tell us how to improve the site to enhance their user experience.
When the user pushes 'submit' on the form, we read the textarea comments from the user, and then programmatically create a filename in that user's subfolder and save their comments to a file. Then we add the filename and path to that user's database record.
The team is not worried about security issues here but I am. Their thinking is "we create the filename, it is 0% based on any user input, and since we write this 'UserX comments' filename and path to the database with no direct user influence -- there is no risk."
My concern is NOT the database activity -- because they're right, the user has no role in WHAT we write to their database record since we're just creating our own filename and storing it in their db record.
My concern is the text file!
So I'm petitioning our small team to rewrite the code to use security to read then write the user's comments in the textarea to the text file.
My concern is -- since we plan to actually READ our user's feedback and open these text files to read them later on -- there might be bad stuff in the textarea that (unless we clean it) could hurt us somehow.
I'm insisting we use strip_tags() but I need to sound informed about the manner in which we sanitize the textarea input -- I'm thinking strip_tags() is the way to go here but I'm 100% new to sanitizing user input. I looked at htmlspecialchars() but that just converts certain characters like '&' to &
and so forth.
Are there other ways to santize/make safe any text the user types into a textarea before we write it out to a file on our web server?
Looks like strip_tags is a good way to go. I'd also suggest writing the file outside of the webroot so that it can't be accessed by a browser.
See also: This Other Thread
If you're not worried about SQL injection, and it seems you're not (either because you know the SQL is sanitized or because you're saving to a text file), then the other problem is the possible XSS attack.
It's easy to ignore those, they don't affect you directly. An XSS attack is an attack that allows one to inject client-side scripts into a webpage. Your database works fine, your server files are not modified, your session files aren't modified either.
This vulnerability is completely client-side. Like I said, it doesn't affect your server. But then someone (i.e.: me) goes on your website, and all of a sudden is redirected to a Warez site while viewing a totally SFW, trusted website. You lose trust from your users. The search engines that crawl your site also mark you as possibly harmful. You lose traffic. You lose revenues. Then again, your server is perfectly fine.
You definitely need to sanitize the user input that is outputted back to the user because of this. Yes, strip_tags is a solution and so is htmlspecialchars or htmlentities.
strip_tags is a little less restrictive however, because it allows you to define some tags you'd like your users to be able to insert in their posts, like bold, links, or italic.
In conclusion, you are absolutely right on insisting on this practice. It doesn't affect you (i.e.: your company's server) directly, but it will affect you at some point if you want a trusted presence on the world wide web.
I know this may be a longer answer than others who should suggest to just strip_tags. They are absolutely right, which is why I upvoted them. Just trying to give you some "corporate" arguments there. :)
It depends on how you are creating a file, and what are you doing with the text after reading it.
If you are using PHP's native functions to write the file, then you should have no problem with remote code execution.
If all you do after reading it is display to a user via HTML, htmlentities(), which effectively makes HTML tags inside the text powerless while still displaying correctly to the user, should be enough.
If you are using it as a part of some query to a database, you should use that database cleaning routine before concatenating it to your SQL. (ie. mysql_real_escape_string() for MySQL, or pg_escape_string() for PostgreSQL).
You may also want to take a look at some info on the OWASP page.
Edit: I forgot to mention, you should also use ENT_QUOTES with htmlentities to prevent single quote injections.
simply use mysql_real_escape_string() to get rid of quotes. htmlentities() if you are worried about js files. That should be about as good as it gets there.
Sanitizing input only protects you from sql injection by removing certain characters. These characters, however, cannot act in a malicious manner from within a text file. I happen to know quite a bit about malware, and trust me, you are not at risk here.
Edit:
If I somehow missed the point of this post through my rambling, do let me know so I can update my answer.
I have a solution that follows mainstream of your development team ideology:
Do not use any user authorization on your site, including admins. Thus, no XSS will harm you either.
I just starting out learning PHP, I've been developing web apps in ASP.Net for a long time. I was wondering if there are any PHP specific security mistakes that I should be looking out for.
So, my question is what are the top security tips that every PHP developer should know?
Please keep it to one tip per answer so people can vote up/down effectively.
(In no particular order)
Always check that register globals are OFF
Always check that magic quotes are OFF
Make sure you understand SQL injection attacks
Turn OFF error reporting in production
EDIT: For the "newbies" out there this is a basic why (and since I have time to explain this):
Register globals is an aberration. It's the ultimate security hole ever. For example, if register_globals is on, the url http://www.yourdomain.com/foo.php?isAdmin=1 will declare $isAdmin as a global variable with no code required. I don't know why this "feature" has made it's way to PHP, but the people behind this should have the following tattooed on their forehead: "I invented PHP Register Globals" so we can flee them like pest when we see them!
Magic quotes is another dumb idea that has made it's way to PHP. Basically, when ON PHP will escape quotes automatically (' become \' and " become \") to help with SQL injection attacks. The concept is not bad (help avoid injection attacks), but escaping all GET, POST and COOKIE values make your code so much complex (for example, have to unescape everytime when displaying and data). Plus if one day you switch this setting OFF without doing any change to your code, all your code and/or data is broken and (even more) vulnerable to injection attacks (yes even when ON you are vulnerable).
Your databse data is your most valuable thing on your site. You don't want people to mess with it, so protect yourself and read things about it and code with this in mind.
Again this can lead to security concerns. The error message can give hints to hackes on how your code works. Also these messages don't mean anything to your visitors, so why show them?
Avoid using register_globals.
Warning: This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0.
Cross Site Scripting (XSS) Wiki, Google
Cross Site Request Forgery (XSRF/CSRF) Wiki, Google (thanks Rook)
Session Fixation Wiki, Google
SQL Injection (SQLi) Wiki, Google
Turn off error messages in Production environments
Keep any "include" code in a directory that is not web-accessible (either deny access or keep it outside of the webroot)
Here's an article I wrote about storing passwords in a secure way, and if you don't feel like taking my word for it, check the links at the bottom.
Also linked in my article, but given its own separate link here, is a paper published by M.I.T. called The DOs and DON'Ts of Client Authentication on the Web [PDF]. While some of its info (recommendation to use MD5 hash, for one) is somewhat out of date simply because of what-we-know-now versus what-we-knew-then, the overall principles are very strong and should be considered.
One of Rooks' links reminded me of another important set of restrictions
Turn off Register Globals (This is the default now, so I hadn't mentioned it before)
When dealing with file uploads, be sure to use is_uploaded_file() to validate that a file was uploaded and move_uploaded_file() instead of copy() or rename().
Read this section of the PHP Manual if you need to know why (and you do).
Since I've now mentioned him twice, check out Rooks's Answer (https://stackoverflow.com/questions/2275771/what-are-the-most-important-safety-precautions-that-a-php-developer-needs-to-know#2275788) as it includes a link to a document which contains (Non-PHP-Specific) information on the most important security concerns (and this therefore probably the right answer).
here is a link of good PHP security programming practices.
http://phpsec.org/
Most of the security issues revolve around user input (naturally) and making sure they don't screw you over. Always make sure you validate your input.
http://htmlfixit.com/cgi-tutes/tutorial_PHP_Security_Issues.php
Always sanitize and validate data passed from the page
In conjunction with #1, always properly escape your output
Always turn display_errors off in production
If using a DB backend use a driver that supports/emulates prepared statements and use without prejudice :-)
don't use "Register Global Variables" and filter user input for xss and injections
Language Vs Programmer. You can write the most serious vulnerability and you won't get a warning or error message. Vulnerabilities can be as simple as adding or removing 2 characters in your code. There are hundreds of different types of vulnerabilities that affect PHP applications. Most people think of XSS and Sql Injection because they are the most popular.
Read the OWASP top 10.
If you're using a mysql database make sure you call mysql_real_escape_string when sending data to the database
There are tons of safety precautions. I can recommend a book Chris Shiflett: PHP and Web Application Security.
http://phpsecurity.org/
Have a look at the Suhosin Hardening Patch, and check out the security vulnerabilities that it addresses.
The PHPSec Guide gives a good overview.
Most of the security issues related to PHP come from using unparsed "outside" (GET/POST/COOKIE) variables. People put that kind of data directly into file paths or sql queries, resulting in file leakage or sql injections.
OWASP provides a lot of insight into security issues that are the biggest problems in applications today. It is nice to see that they have a PHP dedicated page available
http://www.owasp.org/index.php/PHP_Top_5
Always Close you SQL Connection.
Always Release SQL results.
Always Scrub all variables your putting into a database.
When deleteing or dropping from sql use limit 1 just in case.
When developing make sure you have a lock on things to keep the undesirable out. If its open and you know not to load the page right now because it could break something, doesn't mean other people do.
Never use Admin or Root as your server log in name.
Whenever possible, use prepared statements (tutorial. It's almost a must whenever dealing with user input (I say "almost" because there are a few use cases where they don't work), and even when not dealing with input, they keep you in the habit. Not to mention they can lead to better performance, and are a LOT easier, once you get into the swing of things, than piecemeal sanitizing.
Often introductory tutorials don't talk at all about checking data from users. Like all programming environments, never trust the data you get from users. Learn to use functions like is_numeric(), isset(), and mysql_real_escape_string() to protect your system.
There are also features that allow you to access remote files, and other creative things. I'd avoid those until you have a good understand of how and when they work (often they are disabled for security reasons).
Use POST method for data passing from one page to another.
Use trim while getting data like trim($_POST).
Also, use strip_tags for variables before you passing into the queries.
I am suggesting you use any framework link Codeigniter, Laravel, YII, Cake PHP because they maid framework with all securities
I suggest Codeigniter for small projects and Laravel for big projects.
Always use POST and not GET for important Data...
Maybe I am being a bit paranoid, but as I am re-writing a contact module, the following question came to mind:
Can I use unfiltered input in php's native functions?
It is easy to sanitize stuff to put in a database, output to the screen, etc. but I was wondering if for example the following statement could be dangerous:
if (file_exists($_POST['brochure'])) {
// do some stuff
}
If someone somehow managed to post to that page, could the above code be exploited?
The above code is just an example, I can think of other functions I use when processing a form.
Edit: Thanks everybody, the file_exists in the example is actually part of a sanitation function but when cleaning up, php functions are being used so it is rapidly becoming a chicken and egg story: To use functions, I have to clean up, but to clean up I have to use functions.
Anyway, I have got some fresh ideas now.
Yep. All I'd have to do is post "/etc/passwd", or "includes/dbconnection.php" (or anything) to your page, and depending on what //do some stuff actually is, I could possibly delete, modify or read sensitive information. The file_exists function itself won't do anything you wouldn't expect, but you can expect malicious users exploiting your logic.
Always sanitise your user input. Always. If you're expecting to only grab files from one particular folder, don't allow .. or / in the input
By itself, that looks reasonably safe, but it could be used to reveal information. It could allow an attack to check for the presence (or absence) of particular files (e.g. /etc/passwd, /proc/*, etc).
So in this example, you should ensure that $_POST['brochure'] is sanitised first to only accept inputs that match potentially valid file names. Drop any input that contains .., or that starts with a /.
Other functions could have potentially much worse side effects...
PHP's builtins won't do "unexpected" things on bad input (eg, file_exists("foo; rm -r /") will say "no, the file 'foo; rm -r /' doesn't exist")... And if they do, that's a bug you can file against Zend.
Of course, this doesn't stop people from exploiting your code (eg, file_exists("../hidden/shell.php")), so you should still (actually, you should always) be careful when passing user-supplied input around.
could 'brochure' = '../../../../.htaccess'
that's an interesting question.
Apache on my computer is set to deny listing or viewing .ht* and .ini and .php.inc files, but you have me worried now.
You should really be in the habit of filtering all input, but you might like to check out http://www.hardened-php.net/ which distributes a hardening patch and 'Suhosin', which is in many binary distributions by default (OpenSUSE, Mandriva and Debian/Ubuntu)
The fact that you have to ask is your answer. It's not safe.
file_exists() is not as bad as others, but if you don't see the source code for the function you're passing data to, and know how it handles user input, then you're taking a chance.
It's not a good idea to pass unfiltered user data into any php filesystem command. The key with security is that you never allow input to context switch. In this case, your minimum sanitization should be removing path characters.
Always assume a hostile user and the worst they could possibly do if they saw your source code.
Over the years security vulnerabilities have been found in the source of PHP itself, such that functions were suseptable to bufferoverflow style attacks Suhosin is/was a project that patched PHP to remove some of the risk.
I wouldn't trust those functions at all.
This may definitively sound strikingly, however when I closely watch the people and their C code quality in the commits, reverts, etc. over the last eight years, I'm just in constant fear.
What happens with the database string is that it could be retrieved and used somewhere that has a vulnerability. For the answer to your question, think about removing the step where you store the string and then retrieve it. You use it right away, and you have the same risks.