I have built a cms from scratch in PHP and I need a little help with getting it more secure. Basically I have arranged all my important files as followed:
/var/www/TESTUSERNAME/includes/val.php
Is this a secure way to stop people from getting hold of my values ?
Would it be a better to store these values in a database then run the query in this file ?
could you also give me some tips on how to better secure my application ?
First of all, you configure the php installation in such way that it becomes less vulnerable, you can also use the htaccess file to secure your directories.
What about other security issues?
XSS
CSFR
SQL Injection
Session hijacking
Session Fixation
etc
etc
See this for it.
Check POST data for SQL injection, XSS:Filter script (and HTML) inserted to your page.
These 2 are the most important.
And of course update your installation. also you shouldn't rely on Session. If somebody stole a cookie of logged user he change into this user.
If you put the values in the database then you have to worry about SQL Injection. If you aren't using parametrized quires, then you might have a serious problem with SQL Injection and moving the values to the database could be a bad idea due to this increased attack surface. In MySQL SQL injection can be used to read files like val.php, make sure your web application doesn't have "FILE" privileges. You also have to make sure your privileges are setup properly on this file. chmod 750 is a good one of this file, the last number 0 denies all access to everyone that isn't you or in your group.
by keeping the values in val.php you still have to worry about directory traversal vulnerabilities like this:
print file_get_contents("/var/www/whatever/".$_GET['FILE_NAME']);
Go though your code and pay attention to where you are reading and writing to files. Make sure you aren't passing in user control variables. If you want to get an attackers preservative on PHP and learning other ways of how files can be read i recommend reading A Study In Scarlet.
Related
I have my own cms, I'm exploring the security options which I should implement and study.
All my CMS pages are checking of user permissions based on the UserID stored in Session. I was thinking that how much important is it for me to "secure" the forms inside this pages? I mean the users have the opportunity to write SQL statements so if they would want to like use SQL injections it is not really that hard...
So my thinking is to have only the logon page secured + protection against session hijacking, is that correct or am I missing something?
Forms on the front page, query strings etc are also secured.
Thank you for any inside on this.
Securing web apps is a never-ending task. People find vectors to exploit every day (quite literally) through a combination of tools and methods. When building a CMS, you've got to be particularly careful with:
Users being able to log in as someone who they are not
Users being able to remotely inject permanently into a page (especially when combined with above)
Users being able to modify or extract contents of the database they are not supposed to gain access to
All these have to do with form submission, or more generally, userdata entry. It boils down to one simple precept: never ever trust an user.
The first one you have to worry about, and by far the most dangerous, is SQL injection. It's what a lot of companies fall victim to every year, and it is quite in-depth, though most attacks can be prevented by using parametrized queries (TRUE parametrized queries. PDO by default emulates them, there's a config flag to turn on true parametrization). This will effectively do most of the SQL-relevant sanitization for you, leaving the "sensible sanitization" to you (i.e. making sure that a date is actually a date). This protects you from what people tend to call first-order SQL injection - in other words, direct entry.
Second-order is more difficult. It involves storing something in your database that will then get executed in another statement. The CISCO guide has a good idea of how stuff happens.
That's all for SQL to defeat the large majority of script-kiddies.
In terms of content-filtering, you want to use a whitelisting approach rather than a blacklisting one. Remove everything you do not trust or cannot recognize. In terms of HTML, there's a wonderful tool called HTMLPurify that does exactly this.
Also
Don't make the mistake my boss did. Check for the session immediately, not just before rendering the page after the controller has run.
I Just noticed that my mysql_real_escape_string function is not inside a '' in some of my php scripts and it was vulnerable to injections and things like sleep(30) executed on my production site.
I am going the PDO route and implementing the prepared statements after lots of reading here. but this is not implemented yet.
Few questions, I see in my logs that lots of injections where done by people online but I can not see any damages. the user that the site runs to do sql queries has update/select/delete/insert only privileges.
But I am woried things like sleep(30) and what not works and if they did any damages I am not seeing?
Can you tell me where to check for damages or was I safe for at least major damages?
Can they have changed hidden mysql settings or system settings?
By the way, I tried to run latest updates on centos 6+ linux and php.
Thanks
edit:
just to clarify, the database is empty almost and i am not worried about the data being there and the passwords are hashed sh512. so the data inside is not important since this is a new application i am writing. but i am worried if they changed anything on the system or the db i should be worried about. some of the injections i see have java etc but the log is huge and its going to take time to go over it. i also see some schema strings in the injections.
now the question is can they have read my schema info or modified them? why does functions like sleep are working if it is a restricted user? what other functions could they have run?
note i have other DBs in the same MySQL. should i be woried about those?
by '' i mean:
select * from dbname where id=scaped_string
i should have put it in quotes
Checking for damage done to your data is dependent on the kind of data you have in your database. If after careful inspection you don't see anything wrong, then there is probably nothing wrong. If your data is of any decent size, this will be difficult or impossible.
There are many automated bots roaming the internet looking for code vulnerable to SQL injection attacks. Their attempts are probably what you are seeing in your logs. Just because an attempt was made does not necessarily mean an intrusion occurred.
Also keep in mind that you won't necessarily have evidence of data being stolen. The best way to determine this would be to take your server logs and replay them on a copy of your current server, checking to see if you get any data back.
Without any further information, we have to assume the worst case: An attacker is able to read, write, and delete arbitrary data in your database, and possibly even files on your file system, which may lead to compromise of your whole server (e.g. command execution via PHP file, privilege escalation, etc.).
Now let’s have a closer look at the possible impact:
Since PHP’s MySQL extension does not allow multiple statements, so called stacked statement attacks are not possible. So the remaining possibilities depend on the actual statement verb and the context, i.e. the clause inside the statement:
SELECT statement:
Reading any accessible data (e.g. sub-queries, unions, boolean-based blind, etc.)
Reading files (LOAD_FILE())
Writing files (… INTO OUTFILE …)
UPDATE statement:
Obviously updating any accessible data, possibly not just in the current table
Reading any accessible data (e.g. sub-queries, boolean-based blind)
DELETE statement:
Obviously deleting any accessible data, possibly not just from the in the current table
Reading any accessible data (e.g. sub-queries, boolean-based blind)
INSERT statement:
Obviously inserting arbitrary data
Reading any accessible data (e.g. sub-queries)
Some of these may not have a direct impact but may be used to exploit other vulnerabilities. In the end, it depends on the actual vulnerable statement.
As far as I know, there is not hidden mysql setting other than sanitizing your inputs to protect your data from being injected.
You said, you saw lots of injections done by people into the site, and yet you can not see any damage, maybe they were just injecting a plain HTML tags, or trying XXS attacks, because the real mysql injection, can delete your tables, update, reset every data subjected to mysql injection, so if I were you, I would implement PDO right away.
If you have anything like admin panel you should check for webshells and other backdoor-like tools on your server, because attacker could easily read your credentials from appropriate table. And, ofcourse, look for any changes in your pages (look for iframes and suspicious JS code).
Worst case scenario is executing INTO OUTFILE in writeable directory and then accesing it via local include or directly.
But, first of all, before worrying you should consider this as most common automated sql-injection checkers (bots you might say) and if you don't see any damage - mose probably there was no intrusion. But be careful - most intruders nowadays don't look for any visible damage, most probably they will inject some malicious code in your pages (like iframes with their exploits).
So, don't be too paranoid, but still cautious :)
More of a risk assessment question than technical.
So i have been reading a lot about protecting against SQL Injection. Lets assume i have a large web application that is mostly unprotected and i need to make some improvements to protect against this problem. Read large as lots of SQL interaction using dynamic queries but on few (less than 100 registered users).
My question is... If i have already secured the main login script (the only publicly available user input) using parameterized queries, is it really that necessary to do the same work for the rest of the site? I mean if a potential attacker can't log in, how much other damage can he do?
Assuming of course none of my registered users have malicious intent.
Assuming of course none of my registered users have malicious intent.
Never assume that :) If your users have different rights, one with almost no right could find the way to get admin access... And so on.
Also, protecting against SQL injection does not make your login bulletproof and someone could bruteforce through it or simply have sniffed packets from your trusted users. Make sure you protect your whole application, do not assume that the entry point you planned (login script) is the only one available...
And please use SSL if your website contains or requires any sensitive data from your users.
What makes you sure that none of the legitimate users won't attempt to attack your system?
I'm glad my bank don't think that. Some-one would have emptied my account by now, just by using sql injection attacks.
And even then you should be careful about accidents. If you use parameterised queries, someone using a ' in a value won't cause problems.
It allows type safety in your parameters.
It engenders better programming habits.
It allows execution plan caching. (Without it, every query with a different parameter will look like a completely different query. Not only preventing caching of plans for those queries, but over-filling the cache so plans that really can be re-used get discarded.)
Not only is it more secure, it's more reliable. Other than experimentation and throw-away code, I can think of no project where I would have condoned not using parameterised queries.
Never trust your users!
Even if you do (and nobody can sign up either), there's always the potential of CSRF for instance; an attacker would lead users of that system to a seemingly harmless page with an image. That image would have the following code:
<img src="http://yourserver.com/profile?user_id='; DROP TABLE users" />
My hacking skills are practically zilch, but you can imagine what would happen :)
Everything I find on the net tells me to provide the database user and password to connect to the database.
Being paranoid as usual, I don't like this because it means anybody that has the php source can now log into the database and screw with the data. Is this the only way to access the database?
context: http://www.cyberciti.biz/tips/facebook-source-code.html
Yes, it is the only way. Also, as a paranoid you should know that knowledge of login and password is not enough, but you have to login from the right host (which is permitted to log in with this credentials).
Also, as a paranoid, why are you afraid of stealing your sources and not afraid of having vulnerabilities in your code that will allow a hacker to steal data even without login and password? In this case it is better for paranoid to never program at all.
Since PHP will be parsed by the interpreter and only HTML will be output, you need not fear as there will be no way to get hold of the PHP source (guessing that you have set appropriate measures so that the PHP source cannot be downloaded).
Block all traffic to the MySQL server from outside. Only allow localhost to use it.
It's not the only way, but its the way most of the world (like 99.999%) does it, and as far as I can tell, 100% of web programmers.
Consider this: if the password is hardcoded into the source somewhere, why bother? Why not make the account password-less and just limit its access to the web server? Some might say, "oh noooooes!! Don't do that!" But again I ask, what's the difference? What security hole is opened that is not there anyway?
The real security issue is actually protecting yourself from SQL injection. That wide-open account makes you vulnerable if:
1) You have a glitch in code that can be exploited to do something a user is not supposed to do, or
2) They can trick your db server into executing code via SQL injection.
So SQL injection is your big bugaboo to protect against.
There are secondary protections as well. For instance, most people are paranoid about their "users" table that contains users and (unfortunately most of the time) plain text passwords, which are required if you are going to email a user their password.
You can put in a second level of protection on this table (in case they get past your SQL injection protection or find an exploit to make your program do something you thought it would not do) by locking it down so users cannot see it at all or write to it. Then you write two stored procedures, "addUser(username,password)" and "checkPassword(username,password)". This is an example of "security in depth" where you have multiple levels of security around the more sensitive data.
not a lot better but you an specify it in the php.ini
http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.default-password
You need to provide the connection information somehow, but you can mitigate the risk by setting up your MySQL user to have as limited privileges as possible. So grant read/insert access only where needed, and you can set the user host to only allow connections from 127.0.0.1 too.
There are also commercial obfuscation products like http://www.zend.com/en/products/guard/, which might be of interest. I'm not sure if they include string encryption or not though.
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...