![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
Hobbyist Programmer
|
Tutorial - PHP Security
Security is a big concern for any webmaster. However some people don't realize how much of a security risk php can really be. I've even seen some people be able to take over an entire system through php because of a critical flaw that someone didn't think through very well. I'm going to list some tips and fixes so that your php code will be much more secure!
1. Never include/require a page based on user input. The only exception to this is if you are using an if-else checking mechanism and the pages being opened are statically assigned. 2. Never use eval(), its basically the equilvent of System() for C++ programmers and allows you to run any command you want. Even if its use is always the same and unchangable, there should be no reason to use it, unless of course you want to be able to control an entire system through php. But in all honesty if your doing that you'd better make sure everything else is secure and quite truthfully, you should be using something like ssh instead of php. 3. Always check your forms. If your using a page that accesses a database such as MySQL you need to check the users input. A common (yet very unknown) flaw is the use of MySQL Injection. Take a login system for instance. Lets see how it would work normally... username: Joe
password: Smith
-----------------------------
<?php
mysql_query("SELECT * FROM accounts WHERE username='{$user}' && password='{$pass}'");
?>Now lets substitute the variables with the user input and see how it looks... mysql_query("SELECT * FROM accounts WHERE username='Joe' && password='Smith'");Seems ok... but now lets alter our username and password that our user enters. Suppose they enter something different? What will our new query look like then? username: Admin
password: ' OR 'K'='K
------------------------------
mysql_query("SELECT * FROM accounts WHERE username='Admin' && password='' OR 'K'='K' ");Doesn't look too good now does it? When a user enters in input thats going into a query it is basically directly substituted. By cancelling out the original quote and providing the K=K scenerio, the query will always be true. We simply enter a target username that we know exists and if we dont know the screenname at all, we simply use the K=K trick that we did on our password. You might have seen this same trick done on other sites with 1=1. That might work some of the time but if you test it out you'll see that you still have an extra quote to deal with. By using K=K but leaving off the end quote in our input, we have a valid statement. Thankfully there is a fix for it!! I've created a filter script that will cancel out any quotes or other things the user tries to enter. It will also remove any html tags. Always run your input through this script before putting it, or checking it against an SQL query. function apiFilter($filterString)
{
$filterString = trim($filterString);
$filterString = strip_tags($filterString);
$filterString = htmlspecialchars($filterString);
// check for magic_quotes prior to adding more slashes
if ( !get_magic_quotes_gpc() )
$filterString = addslashes($filterString);
return $filterString;
}4. On secure pages be sure to validate the login EVERY time. Here is a common error made by beginners. if($username == "Joe" && password="Smith") $admin = true; .... *later* .... if($admin) DisplayCP(); Not very secure at all. All one would have to do is find the admin url and simply do... admin.php?admin=true; 5. MD5 your passwords. If you or someone on your web-dev team should happen to forget to run the apiFilter script that I gave on some input and someone does manage to bypass your database, don't let them ruin your entire online life. MD5'ed passwords mean very little to anyone. If your passwords aren't encrypted at all, then you risk someone trying out those passwords on your email or IM accounts and such. Although one would use a different password for each and every service they sign up for, I think we can all say that there has been a time or two where our lazy minds simply couldnt remember another password and we used one that we were using somewhere else. I too am guilty of this. When I remember, I change my passwords and come up with new ones. 6. Always be extremely careful with upload scripts. If possible don't use them, but sometimes you simply do need one. Always check the file extension. Either read the string backwords or look for the last occurence of a dot/period. do NOT except the first thing that comes along. This is what leads users to upload crap like "CutePetPicture.jpg.exe". 7. Some of you using flat-file databases might be snickering at the long tip about SQL security. Don't get to smart yet! Be sure that your flat file databases can't be changed or renamed and accessed through any part of your code and be seen by the user. Just use your brain when working with any kind of file or database. We don't wont some faulty input to have our entire database file be echoed back to the user. 8. Not really an issue but I would recommend removing phpsessid from the url. its ugly and more importantly its almost never needs to be seen by the end user and the number one reason to do it is that it can cause compatibility problems with xhtml and they wont validate correctly. Add these two lines at the very top of your page (or edit the php.ini file if you have access to it.) ini_set("url_rewriter.tags","");
ini_set("session.use_trans_sid", false);OR... if you NEED to have phpsessid in the URL yet still want xhtml compatibility then alter your php.ini file like so... arg_separator.output = "&" Well thats about all. I am sure there is a bunch of other things you need to remember as well, but this covers the major stuff atleast. If there is something I missed please let me know. I dont know a whole lot about session or cookie security simply because there is just so much to know, so please see PHP: Sessions. Also I sometime make mistakes. If I said something that was completely wrong or you disagree with me, let me know. Sometimes I simply get off track without realizing it or make a typo like forgetting to leave out the word "not" (very bad thing to do). :o Thanks again! |
|
|
|
|
|
#2 |
|
I eat cake for breakfast.
![]() ![]() ![]() ![]() Join Date: Jul 2004
Location: In my box.
Posts: 4,434
Rep Power: 9
![]() |
Great tutorial. Couple things I'd forgotten in there - ta very much.
|
|
|
|
|
|
#3 |
|
Hobbyist Programmer
|
nice job.
did you mention that people can also use sql injection with getvars? like stuff.php?id=1 stuff.php?id=1' OR '1' also, i have a question, is it possible to inject sql using cookies? like if they have "SELECT * FROM users WHERE username='".$_COOKIE['username']."'" you could change the value of the cookie to contain sql in it. just a few pointers ![]()
__________________
Children in the dark cause accidents, and accidents in the dark cause children. http://www.ronincoders.org |
|
|
|
|
|
#4 |
|
Hobbyist Programmer
|
Yes, you can use SQL injection through GET and Cookies. Pretty much anything. ALL information coming from the client that is going to be processed in a query should be put through some kind of filter such as the one I provided. My advice is if you are using cookies is when a user first visits a page to 1. pull the cookie. 2. filter it. 3. assign it to a session. I'm kinda bias, but I always find sessions to be easier to handle and once you've assigned a session you no longer have to worry so much about security as you would if you kept the cookie the whole way through; you would have to keep checking it.
|
|
|
|
|
|
#5 | ||
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
Quote:
Quote:
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
||
|
|
|
|
|
#6 |
|
Hobbyist Programmer
|
To be honest SQL Injection is quite unknown. I find it a LOT in php code. Infact thats how I joined my school's website staff. I found a flaw in there login script which made it prone to SQL-Injection and no one on the team at the time had even heard of it. Also, I did create that script. Obviously, using common php functions but I did make it by knowing in advanced what needed to be removed and what needed to be checked to make sure text was properly formatted before use.
Sorry if I acted like I discovered or invented something new, because I havn't done anything that hasn't been done before. SQL-Injection is NOT new and neither is my code, although I did happen to write that paticular function though. But yes, NOTHING I wrote about in my tutorial is invented or discovered by me or anything like that. It's just a collection of information I've learned through various articles and things that I've coded. Again my apologies. The last thing I want to do is try to take credit for something I did not do. Simply passing on the knowledge is my only intention. |
|
|
|
|
|
#7 |
|
Programming Guru
![]() Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 4
![]() |
For PHP >= 4.3.0, it's recommended that for MySQL queries, the mysql_real_escape_string function is used. mysql_real_escape_string escapes a few more characters than addslashes does; I'm not sure how significant this is, but it seems like a good idea to use this function over addslashes.
|
|
|
|
|
|
#8 |
|
Hobbyist Programmer
|
Good find Arevos! I looked at the php.net page for mysql_real_escape_string and it does look to be a bit better than addslashes. Just remember to check the status of magic_quotes though. Sometimes programmers will assume a certain setting and if it should ever change it renders their script useless.
Truthfully though, it isnt critical that you use mysql_real_escape_string over the others. Although if your using a newer version of php, go for it! If not, don't sweat it, the important thing is that the quotes are escaped. Nice find Arevos! ;-) |
|
|
|
|
|
#9 |
|
Professional Programmer
|
Thanks a lot, this is a great reference point, the SQL injunction thing is always something that skips my mind
|
|
|
|
|
|
#10 |
|
I eat cake for breakfast.
![]() ![]() ![]() ![]() Join Date: Jul 2004
Location: In my box.
Posts: 4,434
Rep Power: 9
![]() |
You also need to backslash-out hyphens, as -- is a comment marker in SQL:
SELECT * FROM mytable; -- this is a comment Username: me' --
Password: lalala
mysql_query("SELECT userid FROM users WHERE username = '$username' AND password = '$password'");
// SELECT userid FROM user WHERE username = 'me' --' AND password = 'lalala' |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|