Website security is an interesting topic and should be high on the radar of anyone who has a Web presence under their control. Ineffective Web security leads to all of the things that make us hate the Web: spam, viruses, identity theft, to name a few.
The problem with Web security is that, as important as it is, it is also very complex. I am quite sure that some of you reading this are already part of an network of attack computers and that your servers are sending out spam messages without you even knowing it. Your emails and passwords have been harvested and resold to people who think you need either a new watch, a male enhancement product or a cheap mortgage. Fact is, you are part of the problem and don’t know what you did to cause it.
The reason is that security experts don’t like to talk too much in public about what they do and where the issues lie; and sadly enough, they can also come across as arrogant in their views. This could be the result of people not taking security seriously and not following the most basic advice, such as using passwords that are clever, not “password” or “letmein.”
Another reason is those tutorials that show you how to “do something in five minutes” and conveniently neglect to mention the security implications of their advice. If it sounds too easy to be true, it probably is. A perfect example of this is PHP solutions that use a file for data storage and ask you to make it writable to the world. This is easy to implement, but it means that any spammer can write to this file.
Disclaimer: the things we’ll talk about in this article today won’t make you a security expert, just as buying a Swiss Army knife won’t make you a locksmith or buying a whip won’t make you a lion tamer. The purpose here is to raise awareness and perhaps make some of that security mumbo-jumbo a bit more understandable to you.
[Offtopic: By the way, did you know that Smashing Magazine has a mobile version? Try it out if you have an iPhone, Blackberry or another capable device.]
An Interesting Report On Web Security
Web security company Cenzic released a report detailing trends and numbers related to Web security for the first and second quarters of 2009. A PDF of the report is available, and the numbers are telling:

PDF: Web Vulnerabilities Q1/Q2 2009.
Among the most serious vulnerabilities were path traversal, cross-site scripting, cross-site request forgery and SQL injection. Unmentioned are a newer threat, clickjacking, and a user interface issue called phishing. You may have to deal with all of these as a Web developer if you touch PHP and HTML, CSS and JavaScript. Even if you don’t use PHP, you could still cause a lot of problems. Even if you don’t touch code and simply design, you could be a great asset in this area. You could help make the Web safer by making security issues understandable to your users.
Let’s go through all of these things and explain what they are and do. The first thing you need to know, though, is how URIs work.
URIs: The Main Way To Attack A Web Service
The address of any document (i.e. file on the Internet) is its Uniform Resource Identifier (URI). This is what you enter in the browser bar to access the document and what you embed into code to point to the document. For example, my website address is http://icant.co.uk, and the document you see when you open it in a browser is http://icant.co.uk/index.php (the server automatically redirects to that document). The logo image resides at the URI http://icant.co.uk/iconslogo.png, and the image of me pointing at you is on a totally different server and has the URI http://farm4.static.flickr.com/3172/3041842192_5b51468648.jpg.
All of these URIs are okay for you to access. Some URIs, though, contain information that should not be accessible to the outside world. For example, the /etc/password folder on a server contains password and user information that should not leak to the Internet.
Every URI can also contain parameters. These are instructions you can send to the script located at that URI and that are appended to the URI starting with a ? and separated by ampersands. If you want to search for puppies on Google, for example, you can use the URI http://www.google.com/search?q=puppies, and if you want to begin your search after the first 50 results, you can use http://www.google.com/search?q=puppies&start=50.
Normally, these parameters are not entered by end users but rather come from the HTML interface. If you look at the source code of the Google home page and get rid of the painful bits, you end up with the following form:
01 |
<form name="f" action="/search"> |
02 |
<input type="hidden" value="en" name="hl"/> |
03 |
<input type="hidden" value="hp" name="source"/> |
05 |
<input type="submit" name="btnG"/> |
06 |
<input type="submit" name="btnI"/> |
07 |
<input type="hidden" name="aq"/> |
08 |
<input type="hidden" name="oq"/> |
09 |
<input type="hidden" name="aqi"/> |
So in essence, this form sends the content of all of these fields to the URI search and appends them to that URI. This is how you end up with this,
when you submit the form. Notice, for instance, that I have no btnG parameter because I used the Enter key to submit the form.
On the search results page, you can see the pagination links at the bottom (the 1 2 3 and so on under the Gooooooogle logo), and you can see that these links send the same data to the URI and add a start parameter:
1 |
<a href="/search?hl=en&q=puppies&<strong>start=40</strong>&sa=N">5</a> |
You can send parameters to a script with the URI via form fields, links or any other thing in HTML that contains a URI: images, link elements, frames, anything that can take an href or src attribute. If an attacker can override any of these or add a new image to your HTML without you knowing it, they could point to their own URIs and send their own parameters.
You have to be careful with what your parameters contain and where they point to, which could be someone else’s server (to get more code) or sections of your own server that you don’t want to show or send to another server.
Different Types Of Attacks. What Do These Words Mean?
Let’s quickly go through the different items mentioned in the graph above, explaining what they are and what they mean.
SQL Injection
With an SQL injection, an attacker accesses your database by sending an SQL command to your server via the URI or form fields. This is easily worked around by sanitizing, but neglecting to do so can be fatal for your website, as the following XKCD comic shows:

XKCD comic showing how SQL injection would delete a database.
Cross-Site Scripting (XSS)
Cross-site scripting is probably the biggest and most common problem. With it, an attacker injects JavaScript code into your document by adding it to the end of the URI as a parameter or in a form field.
Say you want to be cool and allow visitors to customize certain colors on your page. You could do this easily in PHP:
02 |
// predefine colors to use |
04 |
$background = 'black'; |
05 |
// if there is a parameter called color, use that one |
06 |
if(isset($_GET['color'])){ |
07 |
$color = $_GET['color']; |
09 |
// if there is a parameter called background, use that one |
10 |
if(isset($_GET['background'])){ |
11 |
$background = $_GET['background']; |
15 |
<style type="text/css" media="screen"> |
17 |
/* color is set by PHP */ |
18 |
color:<?php echo $color;?>; |
19 |
/* background is set by PHP */ |
20 |
background:<?php echo $background;?>; |
21 |
font-family:helvetica,arial,sans-serif; |
27 |
<p id="intro">Cool intro block, customizable, too!</p> |
So far, everything’s kosher, and we’re not even using inline styles! If you save this now as test.php and call it on your server in your browser as the URI http://example.com/test.php, you will get a text intro block that is black on white. The $_GET[] variables come from the URI as parameters, and because they are not set, nothing changes. If you want the colors to be red on pink, you can do this: http://example.com/test.php?color=red&background=pink.
But because you allow any value for the variables, an attacker could send the following:
This would effectively close the style block prematurely and add a script to the document. In this case, all we would be doing is writing out the word XSS, but we could do anything that a JavaScript is allowed to do. You can see the results in the following screenshot:

Large view
Once you have successfully injected JavaScript, you will be able to read out cookies; open forms that ask the user to enter their passwords or credit card details; execute viruses, worms and “drive-by downloads”; the lot. The reason is that JavaScript is not bound by any security model; any script on the page has the same rights, no matter which server it has come from. This is a big security problem with JavaScript and is something clever people are working on.
XSS is a very common problem. Websites such as XSSED.org have a field day showing the world just how many websites are vulnerable:

The remedy for XSS is to be very paranoid about anything that comes via forms or the URI. You also need to be sure that your PHP is set up properly (we’ll come back to some ways to test for that and to write good code later on).
Path Traversal
Allowing for path or directory traversal on your server is an amazingly bad idea. You would be allowing people to list the folders on your server and to navigate from folder to folder. This allows attackers to go to folders with sensitive information or website functionality and have some fun. The following screenshot is of me accessing the database of a sandwich company, sending emails from their server and reading the order logs:

Large view
I was able to get all of this information simply by accessing the cgi-bin folder, which was unprotected from being listed. So, instead of going to http://example.com, I went to http://example.com/cgi-bin/ in my browser. I knew something was wrong on their big Flash website when I clicked on the menu. It popped up in a new window and had a URI like
which gave me all the information I needed to play around.
The other problem of allowing folders to be listed is that search engines will index your information, allowing anyone to use Google as a hacking tool. As servers create a page with a title and a headline of the folder name, these are indexed by Google.
You could search for, say, “index of /ebooks” to find electronic books online or “index of /photos” to find photos. To see search tests such as this one, check out the Google a Dream Come True article, which listed many of them in 2003(!).
This method of searching worked much better in the past, by the way: not because people protect their servers better now, but because spammers who offer fake pirated products realize that people do these searches and fake it now to optimize their own websites’ search engine rankings.
Cross-Site Request Forgery
Cross-site request forgery (CSRF) exploits browsers and websites that allow for functionality to be called without really knowing that an actual user initiated it. Say you have a form on your website http://example.com that works with GET and sends things to your database:
01 |
<form method="get" action="add_to_db.php"> |
03 |
<label for="name">Name</label> |
04 |
<input type="text" id="name" name="name"> |
07 |
<label for="email">email</label> |
08 |
<input type="text" id="email" name="email"> |
11 |
<label for="comment">Comment</label> |
12 |
<textarea id="comment" name="comment"></textarea> |
14 |
<div><input type="submit" value="tell me more"></div> |
Forms can be sent by two methods: GET adds all of the parameters to the URI visibly in the address bar, whereas POST sends them “under the hood.” POST also allows you to send much more data. This is a simplification but all you need to know for now.
If the script that adds to the database doesn’t check that the form was really sent from your server, I could add an image to any website by doing this:
2 |
name=cheap%20rolex&email=susan@hotchicks.com&comment=mortgage%20help" width="1" height="1"> |
Anybody coming to my website would now be putting another comment into your database. I could use an image or CSS link or script or anything that allows for a URI to be defined and loaded by a browser when the HTML renders. In CSS, this could be a background image.
CSRF becomes even more dangerous when you are logged into and authenticated by a particular system. An image in any other tab in your browser could execute a money transfer, read your emails and send them on and many other evil things.
A really interesting case of CSRF (albeit an innocent one) occurred in 2006, when Google released its now discontinued Web accelerator tool (GWA). The idea was to pre-fetch websites that were linked to from the current document, thus making surfing faster. All well and good… until you ended up with delete links in websites that worked like this:
1 |
<a href="/app/delete_entry.php?id=12">delete</a> |
Because some applications did not check if this was an initiated deletion or an attempt of GWA to pre-load the page, the tool deleted whole blogs and product databases. Google did nothing wrong, but the community learned a lot about CSRF that day.
Now, you might suppose that moving your forms from GET to POST would make them safe, right? Partially, yes, but an attacker could still use a form and trick people into clicking a button to make the request:
1 |
<form method="post" action="add_to_db.php"> |
3 |
<input type="hidden" name="name" value="bob"> |
4 |
<input type="hidden" name="email" value="bob@experts.com"> |
5 |
<input type="hidden" name="comment" |
6 |
value="awesome article, buy cialis now!"> |
7 |
<input type="submit" value="see beautiful kittens now!"> |
You could even use JavaScript to automatically send the form or a script on another server to do the POST request from the back-end. There are many ways to exploit CSRF, and protecting against it is not that hard.
Remote File Inclusion (RFI)
With Remote file inclusion or code injection, an attacker uses a flaw in your website to inject code from another server to run on yours. It is in the same family as XSS but much more problematic because you have full access to your server (with JavaScript, you can steal cookies and call other code, but you can’t access the file system without resorting to tricks with Flash or Java Applets).
Any code injected to your server with an untested variable and include() command, for example, could run server commands: upload and download and transfer data to other servers, check your server passwords and user names, anything you can do on the command line via PHP or ASP if your server allows for it.
This is probably the worst that can happen to your server, because with command line access, I could turn it into an attack machine for a server network attack, silently listen to everything you and your users do on the server and send it to another Web resource, store information and viruses for distribution, inject spam links, you name it.
The workaround is to turn off globals and to never ever assemble a URI from parameter or form data. (More on that later in the PHP section of the tips.)
Phishing
Phishing is the technique of fooling people into entering information into a bad website. You show end users an interface that looks legit (for a bank or what have you) but that in reality sends their information to your database. Because phishing is a felony, I cannot show you a demo.
The trick with phishing is to make the form really look like it comes from a website you trust. You have probably gotten emails saying that your “XYZ bank account” has been compromised, and you know for certain that this isn’t the case because you have no account with that bank and may not have even heard of it. This is a wild-guess phishing attempt, which is not usually effective.
On the Web, though, an attacker can perform a JavaScript trick to find out where you’ve been. As Jeremiah Grossman showed some years ago, you can use JavaScript to determine the state of a link on the page. Because the colors of visited and unvisited links are different, we can use this technique to figure which websites a user has been to and then display the appropriate logo above the form. This demo shows this quite effectively. Funny enough, you can also use this trick for good; for example, by showing people only the buttons of social media websites they use.
Clickjacking
Clickjacking is a terribly clever way to use CSS and inline frames to trick users into clicking something without knowing it. Probably the most famous example of this was the “Don’t click me” exploit of Twitter a few months ago. All of a sudden, Twitter was full of messages pointing to a website with a button that read “Don’t click me”. Here is an examples for Jason Kottke’s stream:

Twitter’s “Don’t Click” prank, explained
Human nature being what it is, many people clicked the button, which seemingly did nothing. What it actually did, though, was put your Twitter home page on top of the button as a frame, with an opacity of 0 in the CSS. The update field was pre-set with the tweet pointing to the page. The following screenshot makes this obvious, with the opacity set here to 0.5:

By clickjacking, you can make end users do things without knowing it. Every action on a website that can be performed with a simple click can be exploited with this trick.
Clickjacking is a massive problem because it is done via CSS, not a script. Unless browsers block frames from having an opacity of 0, there is no simple workaround. The main counter-measure people take is to disallow embedding in frames using JavaScript. However, with JavaScript off, clickjacking still works.
Source: http://www.smashingmagazine.com
Comments
No comments yet.
Leave a comment