| 
	
 | 
 Posted by Gordon Burditt on 04/29/06 01:53 
>I'm designing a survey form page that will be fairly complex and am  
>becoming confident enough with PHP now to tackle most things. 
>(Thanks to everyone here who has helped) 
> 
>Before I go too far with this I was wondering if anyone could perhaps 
>offer advice or point me to any documents/web pages that could help with 
>ensuring the security of the form/page and site. It is likely that the 
>form will come under attack I expect. 
> 
>Even comments about the best chmod settings are welcome. 
 
PHP pages (with an Apache PHP-module setup) have to be world-readable, 
for Apache/PHP to use them.  In many hosting setups, you FTP stuff 
in under a userID different from the one Apache runs as.  You 
probably want your pages owned by that different userID and mode 
644.  It is preferable that your pages *NOT* be writable by the 
user Apache/PHP runs as, just in case a CGI or PHP page is compromised, 
it can't deface your page.  Put your data in a database, not writable 
files in the document tree. 
 
If you need to protect yourself from a different customer on a 
shared server, you have a lot of problems.  This is much different 
from protecting yourself against users with browsers.  There are 
difficulties with things like hiding your database password, which 
Apache/PHP has to have but that's what the other customer's PHP 
pages usually runs as.  You may want your own dedicated (co-located?) 
server. 
 
>I'd rather not have to wade through another history of the internet book 
>with the words "and be security conscious by using SSL" on the last page  
>which is what most adviice I've found so far boils down to. 
 
SSL provides a way for a thief with a browser to communicate with 
a thief with a web site, making it difficult for *other* thieves 
to perform a ripoff of either first by listening in.  *IF* the guy 
with the browser looks at the cert, he has some assurance of which 
thief he's talking to at the web site.  Very few sites use certs 
for users, and it's way too much trouble for a public site.  How 
many people would notice the cert says "Satan, Prince of Darkness"? 
 
DO use SSL for anything containing credit card numbers and other 
sensitive information.  If your site deals in real money (especially 
if it can spend money using a remembered credit card number), use 
SSL for the login page the user ENTERs his login/password info. 
That it *SUBMITS* to a secure page isn't enough (among other problems, 
the login page is not SSL, so the browser might cache the filled-in 
data.  It also trains users to enter sensitive info into non-secure 
pages without checking). 
 
Don't provide sensitive information to someone who happens to find 
a logged-in user's computer.  Even if you remember the user's credit 
card number, DON'T provide a way to display it in full (last 4 digits 
only is common).  DON'T show the user what his current password is, 
although you can let him change it (which will alert the legitimate 
user when he can't get in).   
 
Be suspicious of input coming from the user's browser.  That includes 
form input, cookies, HTTP_REFERER, variables contained in URLs, 
and browser type info.  All of that can be manually generated by 
typing into telnet. 
 
Session cookies are a bit more secure than other things stored in 
cookies because the user can't fake a session with arbitrary contents, 
they have to fake an existing one, and that's difficult.  Expire 
inactive sessions.  It is less important that you expire inactive 
sessions at 5 minutes vs. an hour, but that you expire inactive 
sessions at 1 week vs. never.  The more unexpired sessions you have, 
the easier session hijacking is.  Also, in the default setup, the 
more unexpired sessions you have, the larger the directory holding 
them gets, and at some point (e.g.  100,000 unexpired sessions) it 
becomes a performance killer. 
 
Do not necessarily depend on PHP's probabalistic session expiration 
(If you set an expiration time of 1 day, there's no guarantee a 
particular session won't be around a month later).  Putting a 
timestamp in the session and using it to figure out if it's expired 
will work consistently.  The probabalistic expiration is good for 
getting rid of unused files, though. 
 
The expiration should depend on the sensitivity of information being 
protected and the estimated magnitude of the "unattended terminal" 
problem.  Don't make it so short your users can't use the site. 
It's not that unreasonable to allow your users 8 hours to submit an 
order (they may be comparison-shopping in another window, or they 
may have to drive home and back to get their credit card). 
 
Don't trust data validation done by HTML or Javascript.  Do it 
*AGAIN* at the server.  (Javascript validation does make it more 
convenient and friendly for users to get instant feedback about 
errors, but it doesn't add to security.) People don't have to submit 
data using YOUR form.  (but don't spend a lot of time trying to 
prevent this: you'll find yourself doing the equivalent of installing 
a nuclear-bomb-blast proof safe door on a cardboard safe with a 
screen back door with a broken lock).  Javascript can be Turned 
Off(tm), or a copy of your page can be set up on another server and 
edited. 
 
Input validation is good, but don't get overly strict about it and 
reject valid input.  Feb 29 *is* a valid date for a birthday. 
People's names sometimes have single quotes in them.  Not everyone 
has a *US* postal code.  The USPS occasionally creates new postal 
codes, so if you use a zip code table, keep it updated and it still 
might be out of date.  Not everyone has a *US* telephone number. 
Some people have telephone numbers with extensions (which are not 
10 digits).  Birth dates are not necessarily representable as a  
PHP timestamp (which on some systems only goes back to 1970). 
 
>I've located standard advice such as using PHP strip-tags on input fields  
>and other PHP specific stuff but was wondering how best to get  
>interactive with the security. 
 
Do not strip HTML tags out of things like names, credit card numbers,  
email addresses, and such.  If you find HTML tags in such things, 
consider them INVALID INPUT and reject them.  It's OK to strip out 
HTML tags out of free-text fields like forum postings. 
 
Beware of SQL injection attacks.  If putting a single quote in a 
text field causes SQL errors, you're in trouble.  Use functions 
like mysql_escape_string() or parameterized SQL (? placeholders 
used for parameters). 
 
>Are there any PHP libraries perhaps that help with this? 
> 
>I'm thinking of things like verifying users ID while they are online  
>without having them email and preventing bots from getting in and things  
>like that. 
 
Do not, under any circumstances, allow user input to be put into 
mail headers (or anything but the "message text" argument of the 
mail() function) without first checking it for carriage-return/linefeed 
characters.  If you detect such characters (e.g. an email address 
consisting of "me@domain.com\r\nBcc: victim1@aol.com,victim2@aol.com") 
DO NOT SEND ANY MAIL AT ALL!  (But you might log the attempt.) 
Don't strip the characters, consider them as invalid input and 
reject them. 
 
Don't put the user-supplied email address in the From: line of the 
mail message.  That can be used to inject headers if they contain 
carriage-return or linefeed.  Also, if it can be made to bounce, 
it can spam that email address with a bounce message. 
 
It is OK to allow carriage-return/linefeed in the body of a message. 
You might want to limit the length of input to something reasonable 
for the situation, or someone will insert whole virus attachments. 
 
A user-supplied email address can be validated by: 
(1) syntax, such as containing an @ and not containing carriage-return/ 
linefeed characters, 
 
(2) Domain lookup, in which you check that the part to the right 
of the @ has either an MX record or an A record in DNS,  
 
(3) Try to send a message to the user and see if the mail server 
accepts it.  This may be no better than (2) (and requires (2) to 
find the mail server).  It also may return inconclusive results if, 
for example, the mail server is down, and it may take an unacceptably 
long time to return such a result.  You should NOT assume that (a) 
the first mail server you try will be up, or (b) domains don't 
occasionally have all mail servers fail or become unreachable. 
(Large sections of the net sometimes become unreachable.) 
 
(4) Send mail to the user and have him click on a link. 
 
Only (4) verifies that the email address given belongs to the user 
and not a victim.  Only (4) is acceptable for putting a user on a 
mailing list (spammers often use mailing list subscriptions as a 
weapon against people who complain about them). 
 
Be careful about sending email to user-supplied addresses.  Your 
site can be used to mail-bomb someone if you do.  Keep track of 
confirmation emails you send and don't send more than, say, two 
plus one a week to any one address (You can take the limit off after 
it's confirmed). 
 
						Gordon L. Burditt
 
  
Navigation:
[Reply to this message] 
 |