Uli's Web Site
On the difficulty of writing safe web sites
A while ago, this server was down because another user hosted on the same physical computer at my hoster's had an open mail relay script, which got the whole thing blocked, including my site.
That reminded me that, maybe, I should write a little piece on why one needs to be very careful when writing one's own web site, and in particular CGIs of some sort, whether they're in C, PHP or Perl.
The main thing to remember is the golden rule of web programming:
Any data coming from the user is insecure.
Many people know this, but few understand that this includes form fields.
It's easy to copy and edit forms. A hacker just does a "view source", copies that into an HTML file, and then changes it to her heart's content. As long as she keeps the form action pointing to our server, she can hand any garbage to the CGI script, including multiple lines in single-line fields, text in number fields... if this is a CGI written in C, this garbage data could do buffer overflow attacks, or even cause zero divisions, if we do not religiously truncate, filter and sanitize the input data in our CGI script.
And there are even Firefox plugins to edit forms on-the-fly, WYSIWYG.
This is the main venue of attack to a web server: Feeding it bad form data, and trying to make it do something it wasn't intended to do. While underflowing lengthrequirements or providing unexpected data generally only shoots down a process on the server, and on most servers at best terminates the hacker's session, overflows have much greater dangers: In theory, hackers could make our CGI write into memory that contains executable code, and then overwrite it with malicious code.
Always filter paths
But that's too complicated. There are easier ways that hackers try to make our scripts fall down. For example, I once came across a site with URLs like this:
But that's not enough. Our hacker is very clever, so she tries http://www.example.com/show.php?file=show.php and suddenly gets to read the raw source code of that server's file that she wouldn't get to see because it gets interpreted. And once she can read the actual PHP script, she might be able to find other venues of attack.
Or maybe she just enters http://www.example.com/show.php?file=/etc/httpd/httpd.conf and then gets to view the Apache configuration file, and now she knows where your passwords file is, what (possibly exploitable) modules you have installed, etc.
Okay, so you go there and prevent any paths that start with a slash. Great, so she just goes and tries ../etc/httpd.conf. "../" means "go one level up". If she does that a couple times, she ends up at the root, which might be at "../../../../", and voila, she has your httpd.conf file. Okay, so you also prevent paths that start with a period? She does: subsections/../../../../../etc/httpd.conf which goes in the subfolder and right back up again, and is equivalent to the ../../../../etc/httpd.conf we just blocked. Defeated again!
Ideally, you'd not allow paths at all. Just reject all paths that contain slashes or "../" sequences. If you need sub-folders, there's one more thing to watch out for: PHP's default installation also accepts URLs as file paths. http://leethaxorserver.com/exploit.php doesn't contain a "../", doesn't start with a slash, but can still compromise your server if you're stupid enough to use include() or require() to embed the file in your site, instead of using fread() and passing it through. Even then, the other user could present arbitrary HTML on your server.
Always strip out delimiters and other significant characters
Another thing hackers love to do is to abuse delimiters. Imagine we have a contact form that sends an e-mail. We've already realized that we can't pass our e-mail address as a hidden CGI parameter, because Firefox and a plugin are all it takes for a hacker to send that mail message to someone else than us. The same goes for sending a CC to the sender. They could just enter any e-mail address as the sender.
But then someone types the following in the subject field:
interesting CC: email@example.comSince e-mail messages contain of a bunch of headers of the form label:value, followed by an empty line, followed by the message text, our original message, which at worst should have been:
To: firstname.lastname@example.org Subject: interesting advertisement goes hereWill suddenly be:
To: email@example.com Subject: interesting CC: firstname.lastname@example.org advertisement goes hereAnd thus send a copy to that victim. Voila, our server is an open mail relay and gets others on it blocked.
So, since we know that the fields in an e-mail header are delimited by line breaks, we make sure what should only be one line really is one line (no matter whether delimited by \n, \r or \r\n).
The same works for other delimiters. If we write something to a list in a file, we make sure any delimiters we use internally are stripped from input data. We make sure that when we take data that we write to an SQL database, it doesn't contain any SQL delimiters. So, if it contains an apostrophe, we turn that into \' to make sure no hacker can end the current string, put a semicolon after it (another dangerous delimiter!) and then start a new SQL command that erases your database, prints out your passwords or whatever. Same goes for PHP, with single quotes, double quotes and other characters. Once hackers' writings get executed as PHP code, they can do anything on our server, e.g. by using the system() function to run grep or whatever.
Watch out for escape sequences
Hackers also like to encode stuff. I.e. you might filter the CGI parameter for newlines, but if they use a percent-escape-sequence to encode the newline, your filter might not catch it because \n and %0A just aren't the same. So, be sure you filter after you've expanded the escapes.
Typing in random URLs
Another approach is to just type in a random URL: http://www.example.com/login.php, or http://www.example.com/.htaccess -- if the server operator didn't block this URL and isn't using a server distribution that blocks such URLs automatically, then the hacker already got our password, or at least the names of the files we don't want her to see. If the server is on a case-insensitive file system, she might try http://www.example.com/.HTACCESS, because that's the same file, but since Apache was written for case-sensitive filenames originally, it didn't consider that the same file as the prohibited .htaccess, and she was able to access it after all.
Still want to write your own web site?
I'm sure I've forgotten some more things in the descriptions above for which I watch out when I write code. The sum total is: It pays off to be paranoid when writing your own CGIs, as easy as it may seem with today's scripting languages. For a web site that just contains contact forms and dynamic directory lists I might risk it.
For a shop system involving confidential customer data, maybe even payment information? Personally, I'd recommend that unless you're a seasoned web developer, you should let a professional do that, or use an existing package that is well-known and maybe even certified. Secure web development and secure desktop programming require a different skill set and having experience in one doesn't make one experienced in the other.
Anything you folks want to add?
Created: 2007-04-19 @946 Last change: 2007-04-28 @028 | Home | Admin | Edit|
© Copyright 2003-2023 by M. Uli Kusterer, all rights reserved.