Forum Moderators: coopster

Message Too Old, No Replies

A Security Checklist

Please post your top tips for security in php

         

vincevincevince

8:37 pm on Jun 30, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I'm starting this thread hopefully so that people new to PHP can become aware of the important security issues - something that the hack-a-script school of php tends to neglect.

1 - Ensure register_globals is firmly OFF, it will stop you making some of the most common scripting mistakes involving people overwriting session variables etc using the url

2 - Use mysql_escape_string() on EACH AND EVERY user submitted string you put into your SQL statements.

3 - For reasonable security, use sessions, and check the value of a variable (eg $userstatus) on every page - try not to use it as true/false, but use an exact number, such as logged in is ($userstatus==74) - this is a great defense against many of the most common forms of attack

4 - Whenever you store a password, only store the md5() hash of the password - that way _if_ someone gets into your database, they don't have a password they can use. To check passwords of later logins, test md5($login_password)==$stored_md5_password

5 - If you use .inc files, set your .htaccess so that php parses them - that way they won't return the source code if someone sneakily guesses/finds out the URL and enters it into their browser.

jatar_k

10:35 pm on Jun 30, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



how do you figure you need to use sessions? If you have nothing to track then why the session? Though if you mean only in "logged in" situations then I would say I agree.

#5 is always good advice or just don't use inc extensions at all or .inc.php works too.

Error Handling/Trapping - check all data and disallow variations or use default cases or catch alls to trap exceptions.

vincevincevince

11:19 pm on Jun 30, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



need to use sessions

Yes, I was meaning logged in cases.

I'll add another one:
place @ before every function likely to give an error - i'm going for database calls and file handling, especially from external sites here - the default error it spews out not only looks bad for your site - but it reveals your actual server path - and possibly your mySql username.

jatar_k

11:23 pm on Jun 30, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



place @ before every function

only once you are putting it live, I know that's what you mean vincevincevince but I just want to make sure everyone is clear.

The @ symbol will suppress error messages and when the site is still in some form of development you will run yourself ragged chasing errors you suppressed.

olwen

11:27 pm on Jun 30, 2003 (gmt 0)

10+ Year Member



5 - If you use .inc files, set your .htaccess so that php parses them - that way they won't return the source code if someone sneakily guesses/finds out the URL and enters it into their browser.

I store my includes below the document root. Is that safe?

jatar_k

12:01 am on Jul 1, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Yes it is, I forgot about that.

Timotheos

12:05 am on Jul 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



This is a great thread.

place @ before every function likely to give an error - i'm going for database calls and file handling, especially from external sites here - the default error it spews out not only looks bad for your site - but it reveals your actual server path - and possibly your mySql username.

I'm no expert on this but I think it might be worth it to do this in the php.ini file ... see [php.net...] . You can turn off displaying errors and have everything log to a text file. This way you don't have to track down every function.

lorax

2:53 am on Jul 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I place my uname, pwd, and mysql_connect call in an include file in a directory outside of my webspace.

Not really directly related to PHP but if you're using an Admin area use SSL - if it's available - to wrap it up.

jamie

9:25 am on Jul 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



good to read the bit about checking all data jatar_k,

i find myself going round the bend if()-ing and else()-ing and ereg()-ing to check all possible GET $vars - nice to know that it is worth the extra trouble!

ukgimp

10:06 am on Jul 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Re Number 5

Care to elaborate. I just looked for some of my inlcudes and nothing showed when snooping around.

security has me worried sometimes. This sort of stuff is interesting.

dingman

6:51 pm on Jul 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



2 - Use mysql_escape_string() on EACH AND EVERY user submitted string you put into your SQL statements.

Might want to gheck the value of magic_quotes_gpc first - escaping twice is safer than not at all, but can still screw up your site.

5 - If you use .inc files, set your .htaccess so that php parses them - that way they won't return the source code if someone sneakily guesses/finds out the URL and enters it into their browser.

Or put them in a directory outside the web root, so there is no URL for them.

Asandir

8:44 pm on Jul 1, 2003 (gmt 0)

10+ Year Member



Never ever trust any input from anywhere. Forms (GET and POST), etc - hell, I don't even trust sessions.

I always code so that unless I state the variable myself in the code, I don't trust it. Probably a little over the top, but it hasn't been too much of a problem yet.

vincevincevince

9:14 pm on Jul 1, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Another I remembered:

Always delete (possibly after backup) any installation scripts supplied with ready made systems, typically install.php or setup.php.

Asandir...

How about a very very commonly used function - taking an email address to save as part of a registration / post to a site / email to. I'll be impressed when you can do that without reading form data :-)

Or did I miss the point?

hpche

12:40 am on Jul 2, 2003 (gmt 0)

10+ Year Member



Also, if you're taking user data on one page and displaying it on another page you should run it through htmlentities() or one of the similar functions at some stage too. Otherwise you/your users could be vulnerable to cross-site scripting attacks and cookie hijacking.

Asandir

3:01 am on Jul 2, 2003 (gmt 0)

10+ Year Member



I meant that I don't trust the input. Not that I don't use input. =)

Every bit of data coming from outside of "my" system gets treated as if it is "hostile" - every bit of data from a form, for example, would all be treated as if they were SQL injects, etc.

What you said in post #1, point 2, really.

ukgimp

7:40 am on Jul 2, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I was told to remove phpinfo, I think that is what it is called as it gives all the server variables for a potential attack.

lorax

1:33 pm on Jul 2, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



>> I was told to remove phpinfo, I think that is what it is called as it gives all the server variables

phpinfo() is actually a function that produces a page with all of those variables. It can be added to a file named what ever you want but yes - if someone were to guess the name of that file, they would have access to all of the server info.

vincevincevince

2:27 pm on Jul 2, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



phpinfo can be disabled - which is a very good idea security wise - but it makes it very hard to find bugs if you are using lots of server variables and such. Another function to disable is mail(), if you are security paranoid - but then you can't send email easily through php.

the disabling of phpinfo and mail are recommended only for where you will let a third party run php on your service - for example you are a host with virtual php enabled domains.

dmorison

5:22 am on Jul 5, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



And delete your phpinfo.php from your production box :)

According to Google, 16,900 webmasters haven't.

Timotheos

8:28 am on Jul 5, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



And delete your phpinfo.php from your production box :)
According to Google, 16,900 webmasters haven't.

Make that 16,899... blush.

Komodo

9:31 am on Jul 5, 2003 (gmt 0)

10+ Year Member



"And delete your phpinfo.php from your production box"

changing the name should be enough, if someone can figure out phpinf0234.php then they will not need the information supplied by it.

ShawnR

10:22 am on Jul 5, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks to all; these are valuable tips. My contribution:

If you take form input, put some sort of flood control on it, such as minimum time between posting from the same IP = 5 minutes; to stop an automated process flooding you.

Komodo

9:21 pm on Jul 5, 2003 (gmt 0)

10+ Year Member



"...such as minimum time between posting from the same IP = 5 minutes; to stop an automated process flooding you."

If guest posting is disabled and you have a limit on post sizes/subject sizes then it is easy to delete posts by user. Minimum delays can piss your members off. The functions to watch out for are anything that sends email, like lost password, registration etc, or any function that works the CPU like Search. As I said, you can always delete posts by user, but the emailer and search use CPU resources which will eventually completely bog the server.

If you have your website virtually hosted, then the host will eventually drop your site to release CPU resources.

Dealing with sessions tables filling is another issue too.

ShawnR

7:47 am on Jul 6, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Whoops! I forgot my manners... Welcome to WebmasterWorld, Komodo.

Not sure I agree with your views, though. You can reduce user irritation by making the delay appropriate for the particular audience. For example, WebmasterWorld uses 15s I think.

You raise good points about controlling the server load, but flood control is important for other reasons too. Here are a few examples:

  • For example, to prevent a vandal from setting up an automated process to submit lots of posts. True, a forum can be moderated, but why get the moderators to work harder than they already do when there are some things that can be automated. Also, there are other applications besides discussion groups/fora.
  • Another example is searching a product database. In this case you want to prevent automated flooding of requests even if it doesn't use much CPU resources. You want to prevent a competitor from downloading your entire database using an automated process.
  • In a similar vein, you want to prevent other sites from using your site as an information portal where they simply serve your content but brand it as their own. Sure, after a while you'll get wise and tighten up your htaccess, but you might as well stop it before it starts.

Shawn

killroy

10:07 am on Jul 6, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



But for usabilities sake don't just have a fixed delay between two posts.

I often have competitors try to extract my database. I even once got a funny email from a microsoft employee complaining he didn't manage to extract my databasse and if I could please send it to him (what ARE they thinking?).

What I did for my ant-hammering is to hae a minimum time before it kicks in, for example 5mins, and then have a threshold of hits/second that will trigger a timed ban, so perhaps a user can do maybe 1 or two hits per second, or perhaps 30 perminute or less. Should stop most extraction spiders. Of course have t obe carefull not to hit any search engines (was easy in my case, I only affected IPs from my country which doesn't host any SEs)

SN

Komodo

11:25 am on Jul 6, 2003 (gmt 0)

10+ Year Member



"True, a forum can be moderated, but why get the moderators to work harder than they already do when there are some things that can be automated."

Well if the forums are set up to run reports like 'delete all posts by user', then it is not a biggy. My comments are based on the preferred denial of service attacks on PHP websites. Whether forums or not, attackers first preferences are always functions that sapp server CPU resources. i.e. anything that dispatches email, registration scripts, then the search scripts etc.

Disabling attacks of that nature means creating a sessions include script that will more accurately determine if it is indeed a browser that is requesting/posting, or a attack script.

Look at the way browers deal with cookies. For instance, 99% of attack apps cannot store cookie data and then return them on future requests from a given proxy/IP.

So create a session based on the requesting IP, which allows it to have persistant data even if the requester is not giving back the PHPSESSID via cookie or URL.

Create a hash based on several different persistant pieces of information, sends it to the requester as a cookie, then have them re-request the document... meaning it ensures the user has the correct cookie before allowing access to any document.

Another way to deal with post floods, is rather than arbitarily forcing delays between posting is to start a counter which would allow say 10 consecutive post requests of say less than 20 seconds apart, if that counter gets past 10, a message tells them they've been blocked to prevent spamming. If that counter gets past 40, then that IP is banned via .htaccess

So each time a document is requested, a random hash would need to be sent to them as a cookie. Whenever they perform a POST operation, it makes sure the cookie they send matches the last hash that was sent.

This will effectively stop attacks made from applications that employ huge anonymous proxy lists.