|
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
[Back to original message]
|