Preface The Rise of Web Security
The development of Web attack technology can also be divided into several stages. In Web 1.0
the era, people pay more attention to
the security issues of server-side dynamic scripts, such as uploading an executable script (commonly known as webshell
) to the server to obtain permissions
. SQL
Injection appeared later , and SQL
the emergence of injection is Web
a milestone in the history of security. SQL
Injection vulnerabilities are still Web
an important part of the security field. Followed by another milestone security issue - XSS
(Cross-site scripting attack). With Web 2.0
the rise of , attacks such as XSS
, CSRF
and , have become more powerful. Web
The idea of attack has also shifted from the server side to the client side, to the browser and the user.
Web
With the development of technology today, a rich and colorful Internet has been built. The vigorous development of Internet business has also spawned
many emerging scripting languages, such as Python
, Ruby
, , NodeJS
etc. Agile development has become the main theme of the Internet. The rise of mobile phone technology and mobile Internet has also brought HTML 5
new opportunities and challenges. At the same time, Web
security technology will also keep pace with the development of the Internet and constantly evolve new changes.
Cross-site scripting attacks ( XSS
) are the number one enemy in client-side scripting security. OWASP TOP 10
Threats have repeatedly listed XSS
at the top of the list, and this article will focus on XSS
the offensive and defensive issues
Preliminary explorationXSS
Cross-site scripting attack , the full English name is Cross Site Script
, the original abbreviation is , but in order to distinguish it CSS
from cascading style sheets ( Cascading Style Sheet
, ), it is called " " in the security field.CSS
XSS
XSS
An attack usually refers to an attack behavior in which a hacker HTML
injects tampered web pages and inserts malicious scripts to control the user's browser when the user browses the web. When this behavior first appeared, all demonstration cases were cross-domain behaviors, so it was called "cross-site scripting". Today, with Web
the complexity of terminal functions and application, it is not important whether it is cross-site, but XSS
the name has been retained.
With Web
the rapid development of development, Web
development has been widely used, from the previous single PC
end to the current mobile end ( APP
, H5
), even including desktop tools, large screens of equipment, etc., so the application scenarios generated are becoming more and more There are many, more and more complex situations, and at the same time, the iterative launch time of most Internet (especially traditional industries) product development versions is very short. In the case of one version a week and one big version in two weeks, the important attribute of security is ignored. Once attacked, the consequences will be disastrous.
XSS
Attack Type Classification
XSS
Attacks can be divided into three categories: reflective (non-persistent), storage (persistent), and based on DOM XSS
;
reflective
The reflective type XSS
simply "reflects" the data entered by the user to the browser. In other words, hackers often need to induce users to "click" a malicious link in order to attack successfully. The reflective type XSS
is also called "non-persistent **XSS**
" ( **Non-persistent XSS**
) .
Usually reflective XSS
malicious code exists URL
, through URL
the function of passing parameters, such as website search, jump, etc. Since the user needs to actively open the malicious website URL
to take effect, attackers often combine various methods to induce users to click.
One of the most basic reflection attacks is: we obtain web page data:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS攻防演练</title>
</head>
<body>
<div id="t"></div>
<input id="s" type="button" value="这是一个按钮" onclick="test()">
</body>
<script>
function test() {
const arr = ['自定义的数据1', '自定义的数据2', '自定义的数据3', '<img src="11" οnerrοr="console.log(window.localStorage)" />']
const t = document.querySelector('#t')
arr.forEach(item => {
const p = document.createElement('p')
p.innerHTML = item
t.append(p)
})
}
</script>
</html>
When a hacker clicks 这是一个按钮
, local localStorage
data can be easily obtained, allowing them to obtain critical information.
storage type
The storage type XSS
will "store" the data entered by the user on the server side. This XSS
is very stable.
A relatively common scenario is that a hacker writes a JavaScript
blog post that contains malicious code. After the article is published, all users who visit the blog post will execute this malicious JavaScript
code in their browsers. Hackers save malicious scripts to the server, so this kind of XSS
attack is called "storage type **XSS**
" .
<!-- 例如我们分别在网站中的输入框中输入以下信息,并保存到远程数据库 -->
<img src="11" onerror="console.log(window.localStorage)" />
<img src="11" onerror="alert(111)" />
page input
alert
When the user browses the page, the pop-up box is triggered and the local data is obtained successively localStorage
:
The above is a typical storage attack.
based onDOM XSS
In fact, this type XSS
is not divided according to "whether the data is stored on the server side", but DOM Based XSS
also reflective in effect XSS
. It is divided separately because DOM Based XSS
the reason for its formation is quite special, and the security experts who discovered it specifically proposed this type XSS
. DOM 型 XSS
The difference with the previous two XSS
is that DOM 型 XSS
during the attack, the extraction and execution of malicious code is done by the browser, which is a JavaScript
security vulnerability of the front-end itself, while the other two XSS
are security vulnerabilities of the server.
Let's look at a simple example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS攻防演练</title>
</head>
<body>
<h3>基于DOM的XSS</h3>
<input type="text" id="input">
<button id="btn">提交内容</button>
<div id="div"></div>
</body>
<script>
const input = document.getElementById('input');
const btn = document.getElementById('btn');
const div = document.getElementById('div');
let inputValue;
input.addEventListener('change', (e) => {
inputValue = e.target.value;
}, false);
btn.addEventListener('click', () => {
div.innerHTML = `<a href=${
inputValue}>链接地址</a>`
}, false);
</script>
</html>
We enter the following text in the input box on the page '' onclick=alert(/xss/)
. The quotation marks here ''
are to close href
the attribute and give it a null value. Then click 提交内容
the button, the label in the page <div id="div"></div>
contains the following html
content
<a href onlick="alert(/xss/)">链接地址</a>
XSS
attack defense
The defense XSS
is very complicated. Fortunately, modern browsers and front-end frameworks/libraries have already done a considerable part of the work for us.
HttpOnly
HttpOnly
It was first proposed by Microsoft and IE 6
implemented in China, and has gradually become a standard. Browsers will forbid JavaScript
access to pages with HttpOnly
attributes Cookie
. So we need to set it in http
the response header to let the browser know that the content cannot be obtained through other methods .set-cookie
httpOnly
document.cookie
cookie
Strictly speaking, HttpOnly
it is not for countering the post- XSS——HttpOnly
resolve hijacking attack. So using it helps mitigate the attack, but still needs other solutions that can solve the vulnerability;XSS
Cookie
HttpOnly
XSS
XSS
input check
We need to be skeptical about user input. The user may enter any string without doing any filtering checks on the input. For example, the content we expect to input is: hello word
, maybe the content we received is onclick=alert(/xss/)
.
In XSS
terms of defense, input checks generally check whether the data entered by the user contains some special characters, such as <、>、’、”
etc. If special characters are found, these characters are filtered or encoded. This way of input checking can be called “XSS Filter”
. There are many open source “XSS Filter”
implementations on the Internet. For example a simple htmlencode
escape:
const htmlEncode = function (handleString){
return handleString
.replace(/&/g,"&")
.replace(/</g,"<")
.replace(/>/g,">")
.replace(/ /g," ")
.replace(/\'/g,"'")
.replace(/\"/g,""");
}
But input checking also has disadvantages, such as
- The attacker bypasses the front-end page and directly uses the interface to submit malicious code to the remote library.
- Input data may also be displayed in multiple places, and the context of each place may be different. If a single replacement operation is used, problems may arise. The input check also needs to be targeted. If we want to express that one number is smaller than another number (
3 < 4
), the character after the front-end escape will become3 < 4
. When this value is stored in the remote end, it will beAJAX
obtained and used It will cause unnecessary trouble, for example, I will perform numerical calculations and so on.
output check
Generally speaking, in addition to the output of rich text, when variables are output to HTML
the page, encoding or escaping can be used to defend against XSS
attacks.
The essence of XSS is still a kind of "HTML injection". User data is executed as part of the HTML code, thereby confusing the original semantics and generating new semantics.
As with input checks, we can encode-escape the output.
1. HTML
Output in
For example, there is such a piece of code in our html code:
<div>$htmlVar</div>
<a href="">$htmlVar</a>
If the output variables are not processed safely, they can be directly used and rendered on the page, which can lead to direct generation XSS
. The final result may generate the following code:
<div><script>alert('我是一个XSS攻击者')</script></div>
<a href="#"><img href="" onclick="alert('我是另外一个XSS攻击者')"></a>
The way to prevent this is to perform escape checks on html
2. HTML
Output in properties
If our html attribute is a dynamic value, then the exploit attribute can also be attacked;
<div id="testXSS" data-name=""></div>
Now data-name
insert an unescaped code into the attribute "><script>alert('我是一个XSS攻击者')</script><"
, the result is as follows:
<div id="testXSS" data-name=""><script>alert('我是一个XSS攻击者')</script><""></div>
3. <script>
Output in label
When outputting in <script>
tags, you should first ensure that the output variables are in quotes.
<script>
// 假设userData是攻击者注入的数据
let xssVar = userData;
</script>
The attacker needs to close the quotation marks first to implement the XSS attack:
<script>
// 假设userData是攻击者注入的数据
let xssVar = "";alert('我是一个script XSS攻击者');
</script>
4. CSS
Output in
The ways of forming in and CSS
, style
are very diverse, so, in general, as much as possible, the output of user-controllable variables in " labels", " label attributes" and " files" is prohibited. If there must be such a requirement, it is recommended to use a CSS escaping library.style attribute
XSS
<style>
HTML
style
CSS
defenseDOM Based XSS
DOM Based XSS
It is a special kind of XSS
vulnerability. The several defense methods mentioned above are not applicable and need special treatment. In essence, it is actually that the front-end JavaScript code of the website is not rigorous enough, and untrustworthy data is executed as code.
If you use Vue/React
the technology stack and don't use v-html
the / dangerouslySetInnerHTML
function, you should avoid the hidden dangers of 、 at the front-end render
stage . There will be a dedicated defense paragraph about that later.innerHTML
outerHTML
XSS
Vue
XSS
There are many places that will be triggered DOM Based XSS
, and the following places are the only way JavaScript
to output to HTML
the page.
document.write()
;document.writeln()
;xxx.innerHTML()
;xxx.outerHTML()
;xxx.innerHTML.replace()
;document.attachEvent()
;window.attachEvent()
;window.location()
;window.name
;
Therefore, developers need to focus on whether the parameters in these places can be controlled by users. If these are used in the project, be sure to avoid splicing untrusted data in the string.
Vue
XSS
defense in
Vue
If you use it as a front-end development framework in your project , congratulations, Vue
it will solve most of XSS
the attack problems for you, but Vue
it is not a XSS
framework for attack prevention, and there are still vulnerabilities to be attacked during development and use;
Vue
defensive measures in
Regardless of using a template or a rendering function, Vue
the interpolated content will be automatically escaped, just like the following template code:
<template>
<p>{
{userData}}</p>
</template>
<script>
// 从远程获取的数据
userData = "<script>alert('xss')</script>"
</script>
The source code content displayed on the page after the final compilation html
is as follows:
<p>
<script>alert('xss')</script>
</p>
The reason is Vue
to help us escape the data, thus avoiding script injection. This escaping is done through browser-native APIs such as textContent, so unless there is a security hole in the browser itself, there is no security hole. The escaped content is as follows:
<script>alert("xss")</script>
injectionHTML
If you want to dynamically inject remote HTML
content, you should first ensure that the content is safe and valid, otherwise you should take some defensive measures to filter or escape some dangerous tag symbols; for example, you can display the rendering like this HTML
:
<!-- 当使用模版时 -->
<div v-html="userProvidedHtml"></div>
<!-- 当使用渲染函数时 -->
<script>
h('div', {
domProps: {
innerHTML: this.userProvidedHtml
}
})
</script>
<!-- 当使用JSX 的渲染函数时 -->
<div domPropsInnerHTML={this.userProvidedHtml}></div>
For example, we can use a simple method (or refer to a more robust library/plug-in XSS to filter the remote userProvidedHtml
data content to ensure security;
// 一个简单的函数,通过转义<为<以及>为>来实现防御HTML节点内容
const escape = function(str){
return str.replace(/</g, '<').replace(/>/g, '>')
}
style injection
Use Vue
the To avoid rendering tag inside the template style
:
<style>{
{
userProvidedStyles }}</style>
This is because, once passed userProvidedStyles
, a malicious user can still provide CSS
the to "click scam", such as styling the link as a transparent box overlaying the "login" button. Then https://user-XSS-website.com/
make it look like the login page of your application, they may obtain a user's real login information, so Vue recommends using 对象语法
and only allowing users to provide specific property
values that can be safely controlled:
<!-- sanitizedUrl应为受控的地址 -->
<a
v-bind:href="sanitizedUrl"
v-bind:style="{
color: userProvidedColor,
background: userProvidedBackground
}"
>
click me
</a>
There is "no silver bullet" for security issues
In the process of solving security problems, it is impossible to do it once and for all, that is to say, "there is no silver bullet".
Generally speaking, people hate troublesome things, and subconsciously hope that the trouble can be kept as far away as possible. And security is a troublesome thing, and it is an inescapable trouble. Anyone who wants to solve the security problem once and for all is wishful thinking. It is unrealistic to "deceive yourself".
Best Practices
The general rule is that as long as you allow unfiltered user-supplied content to execute (whether as HTML
, JavaScript
or even CSS
), you may be putting yourself in a position to be attacked. These suggestions are actually true whether you use Vue
, React
another framework, or even no framework.