The article was first published on my blog

This article will use a few simple examples to understand and learn about XSS (cross-site scripting attacks) for Web security.

XSS

Cross Site Script, originally abbreviated CSS, but to distinguish it from Cascading Style Sheets (CSS), the security domain is called XSS;

XSS attack usually refers to an attack mode in which attackers tamper with web pages through “HTML injection” and insert malicious scripts so as to control users’ browsers or obtain users’ sensitive information (cookies, sessionIDS, etc.) when users browse web pages.

A malicious JavaScript script is injected into the page. The browser cannot tell the difference between malicious JavaScript and normal page content. Therefore, the malicious JavaScript script also has all script permissions. What can a page do if it is injected with a malicious JavaScript script?

  1. Cookie information can be stolen. Malicious JavaScript can retrieve cookie information via “doccument. Cookie” and send the data to the malicious server via XMLHttpRequest or Fetch plus CORS. Once the malicious server gets hold of the user’s cookie information, it can simulate the user’s login on other computers and then transfer money.
  2. You can listen for user behavior. Malicious JavaScript can use the “addEventListener” interface to listen for keyboard events, retrieve information such as a user’s entered bank card, and do a lot of illegal things.
  3. DOM can be modified to fake login Windows to trick users into entering information such as username and password.
  4. You can also generate floating window ads within the page, which can seriously affect the user experience.

XSS attacks can be classified into three types: reflection, storage, and DOM based XSS attacks.

reflective

Malicious script as part of network request.

const Koa = require("koa");
const app = new Koa();

app.use(async ctx => {
    // ctx.body is the data that the server responds to
    ctx.body = '';
})

app.listen(3000, () = > {console.log('Started successfully');
});

Copy the code

Visit http://127.0.0.1:3000/ to see alert execution

To take a common scenario, we control the display content of a page with a parameter to the page URL. For example, we change part of the code above to the following

app.use(async ctx => {
    // ctx.body is the data that the server responds to
    ctx.body = ctx.query.userName;
})
Copy the code

Visit http://127.0.0.1:3000 at this time? UserName =xiaoming userName=xiaoming UserName =

Through this operation, we can find that a user submits a request containing malicious code to the server. When the server receives the request, the malicious code will be reflected back to the browser. This is a reflective XSS attack. Another point to note is that the Web server does not store malicious scripts for reflective XSS attacks, which is different from stored XSS attacks.

In the actual development process, we will encounter such A scenario, an operation on it in the page A, is need to log in to access this button the operation, so you need to jump to the login page and log in again after finish will jump A page, so we processed, jump to the login page, will add A returnUrl parameters, The address is http://xxx.com/login?returnUrl=http://xxx.com/A. If you change returnUrl to a script script at this time, and after the login is completed, If returnUrl is not validated, window.location.href=returnUrl will be executed.

Storage type

The storage type “stores” the data entered by the user on the server.

A common scenario is that an attacker writes a blog post or comment in a community or forum that contains malicious JavaScript code. After the blog post or comment is published, all users who visit the blog post or comment execute the malicious JavaScript code in their browser.

Storage attacks generally go through the following steps

  1. First, the attacker takes advantage of the site vulnerability to submit a piece of malicious JavaScript code to the site’s database
  2. The user then requests a page from the site that contains a malicious JavaScript script
  3. When the user browses the page, the malicious script uploads the user’s cookie information and other data to the server

Take a simple example, a login page, when clicking login, the data is stored in the back end, after login, jump to the home page, the home page requests an interface to display the current user name to the page

Client code


      
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>XSS-demo</title>
    <style>
        .login-wrap {
            height: 180px;
            width: 300px;
            border: 1px solid #ccc;
            padding: 20px;
            margin-bottom: 20px;
        }
        input {
            width: 300px;
        }
    </style>
</head>

<body>
    <div class="login-wrap">
        <input type="text" placeholder="Username" class="userName">
        <br>
        <input type="password" placeholder="Password" class="password">
        <br>
        <br>
        <button class="btn">landing</button>
    </div>
</body>
<script>
    var btn = document.querySelector('.btn');
    
    btn.onclick = function () {
        var userName = document.querySelector('.userName').value;
        var password = document.querySelector('.password').value;
        
        fetch('http://localhost:3200/login', {
            method: 'POST'.body: JSON.stringify({
                userName,
                password
            }),
            headers: {'Content-Type': 'application/json'
            },
            mode: 'cors'
        })
            .then(function (response) {
                return response.json();
            })
            .then(function (res) {
                alert(res.msg);
                window.location.href= "http://localhost:3200/home";
            })
            .catch(err= > {
                message.error('Local test error${err.message}`);
                console.error('Local test error', err);
            });
    }
</script>

</html>
Copy the code

Server code

const Koa = require("koa");
const app = new Koa();
const route = require('koa-route');
var bodyParser = require('koa-bodyparser');
const cors = require('@koa/cors');

// Temporarily use a variable to store it in the database
let currentUserName = ' ';

app.use(bodyParser()); // Process the parameters of the POST request

const login = ctx= > {
    const req = ctx.request.body;
    const userName = req.userName;
    currentUserName = userName;

    ctx.response.body = {
        msg: 'Successful landing'
    };
}

const home = ctx= > {
    ctx.body = currentUserName;
}
app.use(cors());
app.use(route.post('/login', login));
app.use(route.get('/home', home));
app.listen(3200, () = > {console.log('Started successfully');
});

Copy the code

Click login and submit the input information to the big server. The server uses the variable currentUserName to store the current input content. After login, jump to the home page and the server will return the currentUserName. If the user enters malicious script content, the malicious script is executed on the browser side.

Type in the username field

DOM based XSS

Modifying the DOM nodes of a page with malicious scripts is a front-end attack

DOM – based attacks generally go through the following steps

  1. The attacker constructs a special URL that contains malicious code
  2. The user opens a URL with malicious code
  3. The user’s browser receives the response and parses it. The front-end JavaScript picks up the malicious code in the URL and executes it
  4. Malicious code steals user data and sends it to the attacker’s website, impersonates user behavior, and calls the target website interface to perform the operations specified by the attacker.

Here’s an example:

<body>
    <div class="login-wrap">
        <input type="text" placeholder=Enter the url "" class="url">
        <br>
        <br>
        <button class="btn">submit</button>
        <div class="content"></div>
    </div>
</body>
<script>
    var btn = document.querySelector('.btn');
    var content = document.querySelector('.content');
    
    btn.onclick = function () {
        var url = document.querySelector('.url').value;
        content.innerHTML = `<a href=${url}> Jumps to the entered URL </a> '
    }
</script>
Copy the code

Clicking the Submit button inserts a hyperlink to the content of the text box on the current page.

Enter the following information in the input box

' ' onclick=alert('Ha ha, you've been attacked.')
Copy the code

The result is as follows

The href property is first closed with two single quotes, and then an onclick event is inserted. Click the newly generated link and the script will be executed.

It’s also possible.

Defense XSS

HttpOnly

Since many XSS attacks are designed to steal cookies, you can prevent cookies from being obtained directly through Document. Cookie by using the HttpOnly attribute.

The use of a Cookie is as follows

  1. The browser makes a request to the serverCookie
  2. Set when the server returnsSet-CookieHeader to write to the client browserCookie
  3. In theCookieBefore expiration, the browser will send this parameter to all pages in the domainCookie

HttpOnly is marked with set-cookie:

Typically, the server can set certain cookies to the HttpOnly flag, which is set by the server via the HTTP response header.

const login = ctx= > {
    // Simply set a cookie
    ctx.cookies.set(
        'cid'.'hello world',
        {
          domain: 'localhost'.// Write the domain name of the cookie
          path: '/home'.// Write the path to the cookie
          maxAge: 10 * 60 * 1000.// Cookie validity period
          expires: new Date('2021-02-15'),  // Cookie expiration time
          httpOnly: true.// Whether to obtain only in HTTP requests
          overwrite: false  // Whether overwriting is allowed})}Copy the code

It is important to note that HttpOnly does not prevent XSS attacks, but rather prevents Cookie hijacking attacks after XSS attacks.

Input and output checks

Never trust user input.

Input check is generally used to check whether the input data contains some special characters, such as <, >, ‘and “. If special characters are found, they are filtered or encoded. This can be called an “XSS Filter”.

Secure encoding functions

The encoding for HTML code is HtmlEncode (which is a function implementation that turns strings into HTMLEntrities)

& --> &amp;
< --> &lt;
> --> &gt;
" --> &quot;
Copy the code

Conversely, JavaScript can be encoded using JavaScript code.

If the user typed , we would filter the user’s input (if it contains sensitive characters like

&lt; script&gt; Alert (" You've been attacked "); &lt; /script&gt;Copy the code

Transcoding content, such as

Defense against DOM Based XSS

We can go back to the example above

btn.onclick = function () {
    var url = document.querySelector('.url').value;
    content.innerHTML = `<a href=${url}> Jumps to the entered URL </a> '
}
Copy the code

In fact, DOM Based XSS outputs data from JavaScript to HTML pages.

jumps to the entered URL , thus XSS is generated.

So what’s the right defense? Output from JavaScript to HTML page is equivalent to an XSS output process, which requires different encoding processing according to different scenarios

  1. Variable output to<script>Executes a JavascriptEncode
  2. Output to HTML pages via JS
    • Output events or scripts for JavascriptEncode processing
    • Output HTML content or attributes, do HtmlEncode processing

DOM Based XSS can be triggered in many ways, such as

  • xxx.interHTML
  • xxx.outerHTML
  • document.write
  • All inputs in the page
  • Data returned by XMLHttpRequest…

If used in a project, avoid concatenating untrusted data in a string.

Using the CSP

Content Security Policy (CSP) is a trusted whitelist mechanism that can configure the external resources that can be loaded and executed by the browser on the server. We just need to configure the rules, how to intercept is up to the browser implementation. We can minimize XSS attacks in this way.

CSP can usually be turned on in two ways:

  • To set the HTTP HeaderContent-Security-Policy
Content-Security-Policy: default-src 'self'; // Only local resources are allowed to be loaded
Content-Security-Policy: img-src https:// Only HTTPS images can be loaded
Content-Security-Policy: child-src 'none'    // Allow loading of any source frame
Copy the code
  • How to set the meta tag
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
Copy the code

For more information about configuring policies, see the Content-security-Policy documentation

reference

  • Front-end Security Series 1: How do I Prevent XSS attacks?
  • Front-end Security Series 2: How do I Prevent CSRF Attacks?
  • Let’s talk about XSS and CSRF
  • White Hat on Web Security