The TOC:

convention

  • The curly bracketed content that appears in this article is dynamic content for server HTML string concatenation: {userData}, which is often shown as <%= userData > in other articles.
  • The key word used in this article is “user data”, which is synonymous with “untrusted data”.

XSS profile

XSS is a code injection attack in which malicious code is injected and executed on the victim’s browser, essentially a security issue caused by the front and back rendering of untrusted user data.

Untrusted user data refers to user-supplied data, such as values entered by the user in a form, strings concatenated by the user in a URL, and so on. Often manifest as malicious JavaScript scripts or CSS scripts.

Types of XSS

XSS is generally classified into three categories: storage, reflection, and DOM.

Storage and reflection are security issues caused by single service rendering (SSR).

DOM is a security issue caused by client rendering (CSR).

【 storage typeStored XSS (AKA Persistent or Type I)】

1. As the name implies, malicious data submitted by an attacker is stored on the server of the target site (e.g. in a database)

2. The victim visits the target site and the server does not securely process the data used to concatenate THE HTML and sends the problematic HTML to the browser

3. Malicious code is executed in the victim’s browser and attacked

Reflective 【Reflected XSS (AKA Non-Persistent or Type II)】

1, the difference between reflection and storage is that reflection is non-persistent, mostly isomorphic URL parameters for malicious code injection

2. The victim clicks on the malicious URL designed in advance by the attacker to jump to the target site

3. The target site extracts malicious data from the URL, splices HTML and sends it to the browser

4. Malicious code is executed in the victim’s browser and attacked

The DOM model 【DOM Based XSS(AKA Type 0) 】

Amit Klein was the first person to put forward DOM XSS attack. DOM type does not require the participation of the server and is a pure front-end security problem. Everything from the malicious data source to the receiver that accepts and processes the malicious data is in the browser.

Malicious data sources include but are not limited to: URL (such as document.loaction.href), HTML elements, etc.

Receivers that process malicious data such as document.write(), innerHTML, setTimeout/setInterval, eval, and so on.

summary

1. If your project is server-side rendering, and since server-side rendering is almost never purely static, we need to be aware of stored, reflective, and DOM attacks, which can occur.

2. If your project is client-side rendering, only DOM attacks are needed.

The harm of XSS

The data provided by users should always be treated as untrusted data. Once the untrusted data is executed in the browser, such as a JavaScript script, the script will have complete control and can steal users’ private information, such as cookies. A site can be styled to induce clickjacking, a malicious script that can perform any action on the user’s behalf.

Storage and reflection XSS defense

Defending against XSS attacks is not as easy as you might think, but it is also not as difficult as you might think. Storage and reflection require server involvement. We will discuss how to defend against these attacks and whether there are some problems in the case of Vue SSR. There are problems in CSR as well, and we’ll talk about them.

First of all, let’s make it clear that any security problem is caused by the mis-trust of user-provided data. Therefore, any user-provided data should be treated specially and properly handled and displayed if necessary.

1. User data inserted into HTML tags

Case study:

<div>{ userData }</div>
Copy the code

If the content of userData is . The final concatenated string would be:

<div><script>alert(document.cookie)</script></div>
Copy the code

Obviously, the browser will pop up and display the cookie.

Defense mode:

Before the userData is presented to the user, it is HTML escaped, which means that the following characters are transferred to the corresponding HTML entities:

  • & – > &
  • < – > <
  • – > >

  • ” → “
  • ‘ → ‘
  • / to /

This way, the escaped HTML will become:

<div>&lt; script&gt; alert(document.cookie)&lt; &#x2fscript&gt; </div>Copy the code

Does Vue’s SSR or CSR have this problem?

Whether SSR or CSR, there is no problem with template interpolation, i.e. {{}}, Vue will do HTML escape for the data, but there is a problem with V-HTML instructions.

2. User data as a common tag attribute value

By common tag attributes, I mean attributes other than href/ SRC /style and event attributes such as onlick.

Case study:

<div value={ userData }></div>
Copy the code

If the content of userData is:

userData = '"" onclick=alert(document.cookie)'
Copy the code

The resulting HTML content would be:

<div value="" onclick=alert(document.cookie)></div>
Copy the code

Obviously, you have an injection, and you can see that userData is supposed to be the property value of the value property, but this particular string causes it to break the limit of the property value of the value property, which is actually a common way of producing an injection.

Defense mode:

An HTML escape to userData alone is not enough to prevent this type of attack, so our defense should be:

Escape all non-numeric or alphabetic characters as &#xHH; A format in which HH stands for a hexadecimal value or named reference.

The resulting string looks like this:

<div value="" onclick=alert(document.cookie)></div>
Copy the code

This code will be rendered by the browser as follows:

You can see that the entire string is treated as an attribute value of value.

Does Vue’s SSR or CSR have this problem?

SSR: does not exist, Vue will run HTML escape on it when concatenating data

CSR: No, Vue internally uses browser apis such as setAttribute to set node attribute values, which natively avoids this problem

Therefore neither SSR nor CSR will lead to XSS:

<template>
	<div :id="val"></div>
</template>
<script>
export default {
	data() {
		return { val: '" onclick="alert(document.cookie)' }
	}
}
</script>
Copy the code

3. User data as “attribute values for special HTML attributes”

Special HTML attributes refer to URL-based attributes such as href/ SRC /style and event attributes such as onclick. Let’s start with the href attribute.

Javascript: Alert (XXX) :

<a href={ userData }></a>
Copy the code

Suppose userData is:

userData = 'javascript:alert(document.cookie)'
Copy the code

The final HTML string would be:

<a href=javascript:alert(document.cookie)></a>
Copy the code

Well, there’s injection again, and even escaping non-numeric and alphanumeric characters in this string can’t avoid the problem:

<a href=javascript:alert(document.cookie)></a>
Copy the code

This is still the problem code.

Defense mode:

Verify userData strictly using protocol whitelist:

const allowed = ['http', 'https']

const valid = isValid(userData, allowed)
// ...
Copy the code

Or use open source libraries for filtering, such as www.npmjs.com/package/@br…

Does Vue’s SSR or CSR have this problem?

Both SSR and CSR have problems, which can be caused by the following code:

<template>
	<a :href="val"></a>
</template>
<script>
export default {
	data() {
		return { val: 'javascript:alert(document.cookie)' }
	}
}
</script>
Copy the code

Case 2 [User data as full URL] :

Again, here’s the example:

<a href={ userData }></a>
Copy the code

The whole URL content is provided by userData, and we notice that the href attribute value is unquoted, so userData can easily break the feature of “as attribute value”. For example, the content of userData is:

userData = '"" onclick=alert(0)'
Copy the code

The resulting HTML string is:

<a href="" onclick=alert(0)></a>
Copy the code

However, if the attribute value is quoted in single or double quotes, the problem becomes easier, because only the corresponding single or double quotes break the context:

<a href='"" onclick=alert(0)'></a>
Copy the code

As shown above, the href attribute value is quoted in single quotes.

The problem is that if userData also contains single quotes, then this is a problem again. Considering that attribute values can omit quotes, we can’t just deal with single and double quotes in userData and assume that everything is OK.

Defense mode:

For href/ SRC attributes where the expected value is url, the correct response is:

  • 1. Use protocol whitelist to exclude protocols like javascript:.
  • 2. Uris are encoded for userData on the basis of 1. If in JavaScript, encodeURI can be used to encode the complete URL.
  • 3. Make an HTML escape for the urI-encoded content to escape quotes “‘ and so on without breaking the attribute value context.
  • 4. Fully encode the URI for the URL parameter part. If in JavaScript, use the encodeURIComponent function

Does Vue’s SSR or CSR have this problem?

CSR: Does not exist, Vue uses setAttribute to avoid this problem naturally

SSR: Vue only performs HTML escape for URL, but does not encodeURI for complete URL, nor encodeURIComponent for parameter part of URL, which needs to be completed by ourselves.

Case 3 [User data as URL query parameters] :

<a href="https://api.foo.com?q={ userData }"></a>
Copy the code

As shown in the code above, if userData contains such things as double quotes (“), or URL-reserved characters [;,/?:@&=+$] and # signs, it is easy to leave the attribute value context or the URL that caused the error.

This is not possible with encodeURI because encodeURI does not encode URL-reserved characters.

Defense mode:

  • We need to use another function, the encodeURIComponent() function, which encodes the URL reserve character and the # sign.
  • Make another HTML escape for the urI-encoded content to escape quotes “‘ and so on without breaking the attribute value context.

Does Vue’s SSR or CSR have this problem?

CSR: Does not exist, Vue uses setAttribute to avoid this problem naturally

SSR: exists, Vue did not encodeURIComponent for it, we need to complete by ourselves.

4, CSS,

Case 1 [Click Hijacking] :

<a href="{ userData1 }" style="{ userData2 }"></a>
Copy the code

As shown in tag A, its href attribute value and style are completely determined by the data provided by the user, so the attacker can locate the tag to any position on the page. The so-called clickjacking means to make the tag completely transparent through CSS so that the user can’t see the existence of the tag. Then position the tag to a location where the user is likely to click, such as the “Login” link. When the user clicks on the “Login” button, what the user actually clicks is the A tag. Since the href attribute is also completely controlled by user data, the attacker can provide a legitimate URL address, for example: attacker.com/login, a page that looks exactly like the login page of a real website, where users enter their account and password, and attackers complete the theft of the victim’s account password.

Defense mode:

  • Never use user-supplied data to completely control the style of an element

  • You can specify specific CSS property values using user data:

  • Converts all characters other than numbers and letters to the form \HH, where HH represents a hexadecimal value.

  • For details about escaping hexadecimal in the CSS, see www.w3.org/Internation…

Does Vue’s SSR or CSR have this problem?

For clickjacking BOTH SSR and CSR, the following code causes the same problem:

<template>
	<a :href="userData1" :style="userData2"></a>
</template>
Copy the code

This is something that Vue can’t avoid for us, so instead of using user data to define the full style property values, we should carefully use user data to define the values of some CSS properties.

Vue does not exist for CSS-related attacks that are not clickjacking classes, such as malicious user data jumping out of the style attribute context.

Case 2 [URL based attribute Value] :

CSS has many properties whose values are URL-based, for example:

/* associated properties */ background-image: url("https://mdn.mozillademos.org/files/16761/star.gif"); list-style-image: url('.. /images/bullet.jpg'); content: url("pdficon.jpg"); cursor: url(mycursor.cur); border-image-source: url(/media/diamonds.png); src: url('fantasticfont.woff'); offset-path: url(#path); mask-image: url("masks.svg#mask1"); /* Properties with fallbacks */ cursor: url(pointer.cur), pointer; /* Associated short-hand properties */ background: url('https://mdn.mozillademos.org/files/16761/star.gif') bottom right repeat-x blue; border-image: url("/media/diamonds.png") 30 fill / 30px / 30px space; /* As a parameter in another CSS function */ background-image: cross-fade(20% url(first.png), url(second.png)); Mask-image: image(url(mask.png), SkyBlue, Linear-gradient (rgba(0, 0, 0, 1.0), transparent); /* as part of a non-shorthand multiple value */ content: url(star.svg) url(star.svg) url(star.svg) url(star.svg) url(star.svg); /* at-rules */ @document url("https://www.example.com/") { ... } @import url("https://www.example.com/style.css"); @namespace url(http://www.w3.org/1999/xhtml);Copy the code

The url() function also accepts data URIs, such as url(data:image/ PNG; Base64, iRxVB0…). ; .

So if you have the following template:

background-image: url({ userData });
Copy the code

If the content of userData is:

userData = '"javascript:alert(document.cookie)"'
Copy the code

The resulting CSS code looks like this:

background-image: url("javascript:alert(document.cookie)");
Copy the code

This can cause injection problems in older versions of browsers, which can be automatically avoided in newer versions of browsers.

Defense mode:

  • Verify protocols strictly and use protocol whitelists to avoid javascript: protocol.
  • Encode URI Component while preserving URL semantics

Does Vue’s SSR or CSR have this problem?

CSR: Vue internally uses setProperty to set CSS properties for style. There is no out-of-context problem. You only need to verify the protocol whitelist.

SSR: Vue only performs HTML escape for CSS attribute values. If it is URL, Vue does not use encodeURIComponent for URL parameters and the subsequent part, which needs to be completed by ourselves.

5. User data in JavaScript scripts

Case study:

Templates dynamically render JavaScript content, such as:

<script>const v = {userData}</script> or <div onclick="{userData}"></div>Copy the code

Malicious users can easily inject userData by specifying the content of userData as follows:

userData = '""; </script><script>alert(document.cookie)</script><script>'Copy the code

Then the generated HTML is:

<script>const v = ""; </script><script>alert(document.cookie)</script><script></script>Copy the code

So obviously there’s an injection.

Defense mode:

  • Before inserting userData, escape all non-numeric and alphabetic characters to \xHH or \uHHHH or \x{H… H}, where HH is a hexadecimal value.

  • It is important to note that even with escape, some code is still not secure, for example:

  • SetTimeout (‘{userData}’) setInterval(‘{userData}’) Eval (‘{userData}’) should avoid doing this.

  • This is the anti-pattern approach: please never do this, and if you do make sure userData is handled in two ways:

  • Method 1: Use github.com/yahoo/seria… Encode userData, which encodes HTML-related characters such as: ”.

  • Method 2: HTML escape the userData into a hidden HTML tag, then use innerHTML to retrieve its contents and use json.parse to retrieve the data:

  • { htmlEscape(userData) }

    const data = JSON.parse(document.getElementById(‘data-box’).innerHTML)

Does Vue have this problem?

Both SSR and CSR: Vue templates can be rendered

6. Other important matters

Cookie adopt httpOnly

Set the cookie sensitive and used to keep the server session to HTTPOnly, which will prevent JavaScript access.

Adopting Content Security Policy (CSP)

Simply put, the CSP browser side specifies the resource whitelist way, recommended read article:

content-security-policy.com/

【 DOM based XSS】

Although DOM-type XSS is a pure client-side security vulnerability, it is still important to distinguish between code executed on the client and code provided by server-side rendering, for example:

const div = document.createElement('div')
div.innerHTML = { userData }
Copy the code

If this code is sent to the client after server concatenation, then all DOM attacks need to be defended against: storage and reflection XSS. Or see: github.com/OWASP/Cheat… To complete.

As for the content of JS script that has nothing to do with the server, that is, all JS code is not joined and provided by the server, then its defense mode we have explained in the defense mode of storage type and reflection type XSS and whether there is such a problem in THE SSR and CSR of Vue.

DOM XSS is a pure client-side security vulnerability. When a browser renders an HTML page (including relevant JS AND CSS resources), it will identify different rendering contexts based on different inputs and adopt different rendering rules in different contexts, including but not limited to:

  • Normal HTML tag
  • The attribute of the HTML
  • Attribute Value HTML Attribute or CSS property of the URL
  • The script tag
  • Style tags
  • The other…

Usually we only talk about the four subcontexts HTML, HTML attribute, URL, and CSS, because these are the four subcontexts that JavaScript can reach through code, for example:

const div = document.createElement('div')
div.innerHTML = userData
document.body.appendChild(div)


Copy the code

The code above enters the HTML subcontext in the context of JavaScript execution using the innerHTML attribute of the tag element.

conclusion

This article try to cover most of the XSS related safety knowledge, but it is difficult to cover the complete, even the author in the process of finishing has selective abandoned some knowledge, but the content of the main basic have reflected, security problem is a need to according to the different scenarios, such as different context and different context of rendering) using different defense way, So the fundamental thing to learn is to understand what capabilities are available in different contexts and what impact those capabilities have if controlled by the user. We’re better at defense if we know the basics, not if we memorize them.

Escape implementations in different contexts can be referenced

Github.com/ESAPI/owasp…

Github.com/chrisisbeef…

References

  • Owasp.org/www-communi…
  • Cheatsheetseries.owasp.org/cheatsheets… ‘
  • Vuejs.org/v2/guide/se…
  • Github.com/OWASP/owasp…
  • Docs.huihoo.com/google-ctem…
  • Github.com/OWASP/Cheat…