Vulnerabilities in JavaScript: Secure coding insights and tips

JavaScript vulnerabilities are on the rise in India with the entry of HTML5 and faster JavaScript engines. Here are some key problem areas along with antidotes.

When the words ‘Java’ and ‘security’ are used together, a common assumption is that the reference is to server-side Java. Myths abound here, such as the belief that security is a server-side concern and that JavaScript itself cannot have security issues [see box: JavaScript myth busting]. However, in recent times, with the popularity of Web 2.0, Ajax and rich Internet applications, JavaScript and its attendant vulnerabilities have become highly prevalent in Indian organizations.

JavaScript myth busting

The perceptions that critical operations are performed on the server side and that all data is stored there are incorrect. What many browsers do today involves reaching out over an unencrypted connection to an unverified site, grabbing code and executing it.

Client-side storage is gaining prominence with HTML5. Client-side logic is also on the rise, as this is an opportunity for developers to offload processing to the user, saving bandwidth and machine-time. In reality, all server-side data and functionality can be accessed from the browser using JavaScript.

Securing client-side JavaScript is a problem that has started receiving attention. Third-party JavaScript issues from widgets, embedded code and JavaScript libraries are some of the vulnerable aspects of JavaScript that see active exploitation. This article looks at vulnerabilities in JavaScript and possible best practices for secure JavaScript coding.

JavaScript security issues can be divided into three broad categories:

1) DOM-based cross-site scripting (XSS)

Most security professionals are familiar with cross-site scripting (XSS). While XSS is usually the result of insecurely written server-side code, DOM-based XSS is a kind of XSS occurring entirely on the client-side. With server-side XSS vulnerabilities getting fixed, a shift in focus towards DOM-based XSS is indicated. DOM-based XSS is more serious than ordinary XSS attacks, since such scripting cannot be filtered through a web-application firewall (WAF).

The script injection in DOM-based XSS happens purely on the client-side. Looking for DOM-based XSS is tricky. JavaScript static analysis requires identifying sources and following them into sinks, while JavaScript runtime analysis requires execution and awareness of when and where sources/sinks are being called for execution.

JavaScript sources are functions or DOM properties that can be influenced by the user. Vulnerable JavaScript sources that can be exploited for a DOM-based attack include the following:

  • Location-based, such as location, location.href, document.URL and so on.
  • Client-side storage based. For instance, it could be document.cookies, sessionStorage and localStorage.
  • Navigation-based, such as navigation.referrer, window.name, history et al.
  • Cross-domain functions.

JavaScript sinks are properties, functions and other client-side entities that that can lead to or influence client-side code execution. Here are some common exploitable JavaScript sinks:

  • Execution-based, such as eval(), Function(), setTimeout(), setInterval() and so on.
  • URL-based, for instance location and location.assign().
  • HTML-based, such as document.write(), HTML elements and attributes.
  • XHR calls, postMessage, client-side storage and other JavaScript variables.

DOM-based XSS usually happens when source data is put into a sink without proper validation. Sink functions such as eval(), setTimeout() and setInterval() are dangerous, since they make it possible to execute even text passed through them. The input to these functions is controlled completely on the client-side. Completely eliminating the use of eval() is strongly recommended. If used, no user controlled data must be passed through these functions.

In order to mitigate DOM-based XSS it is a good policy to avoid using sources/sinks whenever possible. When unavoidable, perform rigorous white-list based filtering on sources and perform proper encoding before sending data to a sink.

2) Cross-domain information leakage

JavaScript has cross-domain functionality that allows sites to load multiple objects from various sources (widgets or iframes, among others). Until recently, JavaScript had restrictions on accessing/sending data to other domains. However, HTML5 has increased the level of cross-domain access that JavaScript enjoys with the cross-domain XML request function.

When not implemented properly, the use of this function leads to unintentional data leakage. It is best to use a whitelist-based approach when implementing this function—right down to the sub-domain level. This ensures that anonymous JavaScript cannot be executed through public sub-domains.

postMessage is a JavaScript function under HTML5 that facilitates communication across iframes, i.e. two iframes loaded from separate domains on the same page or between the page and an iframe within it. This communication is entirely client-side. If postMessage restrictions are set loosely, it could result in invalidated malicious data being sent across iframes or a potential data leak scenario making it possible to perform data extraction across sites. The white-list paradigm applies here as well.

Prior to HTML5, cross-domain requests were handled using JSON callbacks. Using callback functions in APIs should only be allowed with discretion in cases where the information in question needs to be shared with any and all external parties. Turn these features off when not needed.

3) Client-side logic and data storage

Initially, JavaScript performance and capabilities were very limited, receiving no significant focus from browser developers for improving performance. As JavaScript engines get faster with iterations of browser release, it is possible to perform substantial processing on the client-side.

This can tempt developers to consign sensitive operations to the client-side. While this is unavoidable in some scenarios, it may also be intended to offload processing to the client-side and save server-time and bandwidth.

With HTML5, client-side storage mechanisms have gone beyond the cookie with newer options such as localStorage, Web SQL and IndexDB. Storage of sensitive data on the client side using these mechanisms fosters a huge security risk, bigger than cookies ever posed. These methods unlike cookies, have a longer life-span and larger storage capacity which tempt developers to use them to store potentially sensitive data. Moreover, JavaScript’s weak encryption libraries make it likely that developers would merely encode this information rather than encrypt it.

A real world example is hard-coding the username and password into the JavaScript on the client-side. Implementing logical decision-making on the client-side makes the code available to the user. This can result in the user attempting to influence the outcome, since the whole decision making happens within the browser — an environment that the user has full control over.

Operations involving security controls, sensitive logical decision-making and authentication should be avoided on the client-side. Remember, merely disabling right-click functionality or obfuscating code does not prevent access to JavaScript.


https://cdn.ttgtmedia.com/rms/security/Lavakumar_Kuppan_mug.pngAbout the author: Lavakumar Kuppan is the author of IronWASP, an advanced Web security testing platform. He has also authored multiple other security tools like 'Shell of the Future', JS-Recon, Imposter and the HTLM5 based distributed computing system—Ravan. As a security researcher, Lavakumar has discovered novel attacks that include a sandbox bypass on Flash Player, WAF bypass technique using HTTP parameter pollution, multiple HTML5 attacks and a CSRF protection bypass technique using CickJacking & HPP. His research and tools are available at the Attack and Defense Labs website.

(As told to Varun Haran)


Read more on Application security and coding requirements

Data Center
Data Management