Cross-site scripting (XSS)
One of the most popular forms of cyber attack, targeting web applications – specifically their frontend part. This attack was first discovered in 1995. It consists of injection of a malicious code into our application and then executing it by the user browser.
Types of attack
This kind of attack can be divided, for its durability:
- Persistent (stored) – it is most dangerous variety in which the attacker is able to force the server to save malicious code, which means that it will be rendered on each newly opened page. Such an attack has a greater reach and allows for its further self-propagation within the compromised application, reaching far more potential victims.
- Non-persistent (reflected) – in which attacker is able to insert malicious code but only temporarily – until the user closes the page. This form of attack is executed mostly when the application is attempting to render the page data received from the user without properly escaping it in the first place.
and source of injection:
- Server-side – where the code was injected on the server side, so it is persistent
- DOM-based – where malicious input was added only for just one session by the client-side app
In this article, for obvious reasons, we will focus our attention on the latter, the least dangerous – from a range perspective – exploiting vulnerabilities in the client-side code.
- Access to global objects
- Access to cookies
- Access to Web Storage
- Access to hidden from inputs
- Ability to manipulate site interface (for example it could create a prompt asking user to provide sensibility data)
The attacker can easily send obtained information to any server located in the different domain.
Additionally injecting simple
<script> tag opens up the possibility to fetch external, more complicated code from any source.
Understanding DOM-based XSS
This attack occurs when we are inserting on our site non-validated data from a untrusted source. Places in the code of our application, in which we use this information in a potentially dangerous way, are called “sinks”.
- Web storage
- user input
- Execution sinks
- Control flow sinks
- HTML manipulation sinks
- Style Sinks
- XMLHttpRequest sink
- Set Cookie Sink
- Set Location Sink
- JSON sink
- XML sink
- Third-party lib sinks (jQuery)
Getting URL hash location and then inserting it as it is into the document by using not safe
Content Security Policy is the primary method of defence against cross-site scripting attacks, regardless of their type. You will learn more about it later in this article.
Other notable rules which worth keep in mind include:
- Filtering and validating all inputs which come to our application (including data received from our very own server, which could be compromised in a different way)
- Proper encoding our application output, depending on the context in which they can appear
- Do not use methods that convert strings into executable code
innerHTMLDOM API property and its similar third-party counterparts by other, safe methods:
In the era of modern SPA applications, defence against XSS attacks due to the rare necessity of the manual DOM manipulation falls onto libraries and frameworks which we are using to build them. That’s why we need to make sure that tools we are using are properly protected from this kind of attacks as well as we should avoid using low-level DOM operations on the structure of our documents.
The purpose of the attack is to force the user to execute a specific action on the infected application. The attack is done through changes in the interface or behaviour of the application.
- The attacker is placing a
<iframe>element on his site, which is then located on the transparent layer above the content which the user can see. The victim is convinced that he is clicking on an item that he sees on the page he is actually visiting but as it turns out the click takes place on the invisible document that the attacker hides from him.
- The attacker can force the user to click on a different element that he wanted to by hiding mouse pointer and replace it with a false one (cursorjacking) whose position in the browser window is very different than the actual one. In that way, the user who is convinced that his mouse pointer is in some specific area of the screen, for example above the “Book Flight” button, is pressing it and he is activating the delete account procedure because real pointer position was on “Delete my account” button.
Because the attack is done by nesting the application inside another page through the
<embed> elements, an effective defence method is disabling this capability via the CSP
Cross-site request forgery (CSRF/XSRF)
This is a special type of attack, unlike the others, it is directly targeting user’s browser, not the web application itself.
It consists in forcing the browser to make a false request (generated by the attacker), to a vulnerable application to perform a specific action on it, such as registering a new account, removal of certain resources or in the case of electronic banking system applications – transfer money to the attacker account.
Typically, this type of attack is based on the assumption that during it the victim will be logged on to his account and will, therefore, have the rights to allow the browser to call the malicious request.
An attacker is able to execute a GET request, for example, using an
src attribute of the
Or POST request through the
<form> element like presented here:
The course of the attack
- The attacker places the code calling the specified action:
- on his own site
- on the attacked site, utilising the XSS vulnerability
- The victim visits a malicious website
- The browser without his knowledge automatically sends a malicious request
- The vulnerable server considers this request to be harmless and executes the attacker’s command
There is plenty of techniques helping you prevents such attacks. On the front side, the most important thing to do is to prevent malicious code from being placed within our application (XSS vulnerability), thereby closing opportunity to even more effective attack.
- Once logged in, the application sets a cookie containing a special random token that remains unchanged for the duration of the session.
- Before the request is made, the server verifies the token’s correctness
AngularJS framework has such a protection built in.
The above method is based on the assumption that only the code of our application which is running within the same origin will be able to read data stored in cookies, so it is important to protect against cross-site scripting.
Network eavesdropping and man-in-the-middle (MitM)
As its name suggest this attack involves listening of non-secured network traffic between victims computer and the web application, for example in a situation when the victim is using a public wireless network.
MitM attacks take a similar form, but unlike the previous one, the attacker is able to modify the transmitted data as the network traffic passes through the controlled by him the portion of the network.
The attacker can capture confidential information such as banking account authorization data, credit card numbers or finally he can bypass application security mechanisms, for example by reading the session data contained in the cookies.
Hacker is able to change victim’s actions, for example by changing the bank account number in the money transfer request, as well as modify the response sent to him by the server, so that he did not realise he was the victim of fraud.
The main defence mechanism against both attacks is to force a secure, encrypted SSL/TLS connection.
An encrypted connection is the best way to ensure that the transmitted information has not been read, amended in any way, and the parties involved are truly the ones who they say they are.
HTTPS is an encrypted variant of the HTTP protocol for sending hypertext documents, where all communication takes place by using lower cryptographic protocols such as SSL and TLS.
Both protocols provide:
- confidentiality – data cannot be read by third-parties
- integrity – no possibility of interference in the transmitted information
- authenticity – that is, the assurance that the parties giving the information to each other, in fact, are the ones who they say they are
TLS is a successor to the older SSL standard and therefore is considered to be safer.
It is important to make sure that all resources on the site are served via HTTPS, to avoid mixed content issues.
The encrypted connection provides a certain degree protection against eavesdropping and man-in-the-middle attacks.
SSL and TLS are not 100% secure because such security cannot exist. There are very well-known attacks on these protocols and the new ones continue to emerge. Despite this they are the best way to achieve communication security which has been proven through the launch of Google “HTTPS Everywhere” campaign encouraging developers to use secure TLS connections, which becomes much easier thanks to initiatives like “Let’s Encrypt”, which issue free certificates. As part of its campaign, Google modified its search engine algorithm to take into account HTTPS as the indicator for a higher ranking score for sites that are using it.
Also, popular browsers warn against visiting unprotected sites.
Same-origin Policy (SOP)
It says that the given script is only allowed to get access to only this resources which are under the same execution context, i.e. they have the same origin.
What is the origin?
Origin is a combination of the scheme, fully qualified hostname and port number, all of which are derived from the URI of the page to which given context belongs. We say that two documents have the same origin if the scheme, hostname and port are exactly the same for both.
It means that, even if we load script from an external domain, its origin will be derived from our site URI.
The above rule opens the gap for cross-site scripting attacks and in order to counteract this, the Content Security Policy was created.
The main task of SOP is to prevent scripts running on one site from interfering with resources of another.
If a user at the same time has opened both his booking site where he is logged in, as well as the malicious site that wants to access his account then the browser will not allow for it, as the scripts have a different origin. Because of that hacker cannot manipulate the booking site in any way.
Sometimes it is necessary to send information between different origins, for example when a website uses subdomains. For this purpose, standardised mechanisms such as CORS, Cross-document messaging and WebSockets which are all built into modern browsers can be used.
Content Security Policy
It is a tool designed to prevent code injection attacks, mainly XSS. We use it to tell the browser which resources it can load and what scripts it can execute (whitelist mechanism).
CSP consists of the
Content-Security-Policy header which takes as its value a set of directives that provide control over resources that a browser can load.
This header can also be used as a
<meta> element of the page. Excluding some directives.
List of available policy directives
- scripts-src – specifies the pool of addresses from which scripts can be loaded, self value prevents the use of inline scripts
- style-src – the equivalent of the scripts-src for styles
- base-uri – list of allowed URLs for the
- child-src – list of valid sources for web workers and elements nested in frames
- connect-src – restricts the number of URLs from which resources can be loaded via script interfaces
- font-src – specifies valid sources for the
- form-action – list of valid endpoints to which web forms can connect to
- frame-ancestors – specifies valid parents that may embed a page using
<applet>elements; cannot be used as a
- img-src – list of allowed URLs from which images can be loaded
- media-src – same as
img-srcbut for audio/video files
- object-src – same as above but for
- plugin-types – it is limiting types of allowed plugins for a site
- report-uri – indicates the URL where the browser will send reports if the CSP rules are violated; cannot be used as a
- upgrade-insecure-requests – it makes it easy to automatically migrate content to use HTTPS protocol
- block-all-mixed-content – instructs the browser to never load resources from mixed sources (e.g. load resources only available through HTTP when the page is served through HTTPS)
- With CSP, you can disable inline scripts, and specify a list of trusted scripts, thus practically eliminating XSS attacks
- CSP can also help to migrate a site to HTTPS by:
- forcing to load resources through secure connection even if in the URL the HTTP protocol is specified
- blocking content that cannot be served by a secure connection, thereby removing the warning raised by the browser about mixing content
Cross-origin resource sharing (CORS)
CORS is a mechanism that is part of the W3C specification, whose main intention is to make it possible to specify which sites from a different domain can use our resources.
Thanks to CORS, developers may circumvent the restrictions imposed by the Same Origin Policy without turning it off (what cannot be done programmatically anyway).
Technically, CORS is nothing more than a special HTTP header, which exchanges information between the client application and the server, based on which both parties decide whether to allow such a request.
- Request headers
- Origin – specifies from which domain the request comes from
- Access-Control-Request-Method – used in preflight requests to determine if a requested method is allowed
- Access-Control-Request-Headers – used in preflight requests to check if the given method headers are allowed
- Response headers
- Access-Control-Allow-Origin – specifies which domains are allowed to make requests
- Access-Control-Allow-Credentials – used in preflight requests, to if the actual request can be made using credentials
- Access-Control-Expose-Headers – indicates which headers can be exposed as part of the response
- Access-Control-Max-Age – determines how long the result of a preflight request can be cached
- Access-Control-Allow-Methods – used in preflight requests, to specify which methods are allowed
- Access-Control-Allow-Headers – used in preflight requests, to specify which headers are allowed
Types of requests
- Simple – in this form of request, the server returns the response immediately, provided that it supports cross-domain requests
- Preflight – in this case, the client first sends a request asking whether the specified action is allowed and only after a response from the server, the actual request is made
With preflight requests, the server can prompt the client for credentials.
CORS allows you to separate the frontend from the backend, allowing for better scalability of the applications being built.
However, the most common use case is when you want to utilise an external API located on the service provider server, which would otherwise not be possible.
The HTTP cookie is a small piece of information (up to 4096 bytes) that is sent between the client and the server.
It is used to keep state for the stateless HTTP protocol.
Need to secure
Data kept in cookies is stored by the browser on his machine in unencrypted/unprotected form as key-value pairs in plain text files. Anyone who has physical access to this files can modify the information that is stored there. This can also be done by the installed malware.
From the client application level, only SOP-compliant scripts can read and change the values stored in them. But here, we cannot forget about XSS attacks by which malicious code can access them as well.
It all makes, that they cannot be regarded as a trusted source of information.
Make cookies more secure!
Send your cookies over HTTPS only
Be sure to send cookies through a secure connection to prevent information stored in them from being read. In that way, we will protect them from eavesdropping or man-in-the-middle attacks.
To enforce this behaviour, you need to set the
Define the boundaries of where your cookie can be sent
Domain flags are used for this. By using the first we will define a path, which determines the upper limit where our cookie will appear. The second option will give us the possibility to choose an exact domain to which the cookie will be limited.
Be sure cookie can be sent from your domain origin
SameSite flag, we can exclude the last vulnerability that our cookie is exposed to. Unfortunately, at the time of writing this article, only browsers based on the Blink engine (e.g. Google Chrome, Opera, Vivaldi etc.) supports it.
Web (DOM) Storage security
Unlike cookies data held in Web Storage is encrypted by the browsers running on certain system platforms. This makes it more difficult to get physical access to them, but it does not prevent it completely since there are available tools used to read them.
What can we do to make it secure?
With the skilful use of Web Crypto API, we can achieve not only the security of stored information but also their integrity.
Where to store security tokens?
We can use both cookies and Web Storage to store security tokens. The latter is used much more often because it has a much higher size limit.