XSS

XSS(Cross-Site Script)

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

注入流程

  • 黑客往网页里注入恶意脚本代码
  • 当用户访问数据时获取到包含恶意代码的网页
  • 通过恶意脚本,黑客可以获取和控制用户信息

原理

HTML是一种超文本标记语言,通过将一些字符串特殊地对待来区别文本和标记,(<)被看到是HTML的标签的开始。当动态页面中插入了一些特殊字符,用户浏览器会将其误认为插入了HTML标签,当这些HTML标签引入了一段javascript脚本时,这些脚本会在浏览器中执行。所以当遇到这些特殊字符不能被动态页面检查或者检查出失败时,就将会产生XSS漏洞。

特点

与钓鱼攻击相比,XSS攻击带来的危害更大,有一下特点:

  • 由于XSS攻击在用户单签使用的应用程序中执行,用户将会看到与其有关的个性化信息,入账户信息等等…,克隆的web站点不会显示个性化信息。
  • 通常 在钓鱼攻击中使用的克隆web站点一经发现,就会立即被关闭
  • 许多浏览器与安全防护软件产品都内置了钓鱼攻击过滤器,可以阻止用户访问恶意的克隆站点。

XSS可以大致分为反射型、储存型、DOM-Based三种。

反射型(非持久性)XSS

通过诱导用户点击恶意链接来造成一次性攻击。也是最普遍的类型。

一般流程如下:

  1. 黑客把带有恶意脚本代码参数的URL地址发送给用户
  2. 用户点击此链接
  3. 服务端获取请求参数并直接使用,服务器反射回结果页面

特点

  • 反射型XSS攻击是一次性的,必须要通过用户点击链接才能发起
  • 一些浏览器内置了一些XSS过滤器,可以防止大部分反射XSS反射
  • 反射型XSS其实就是服务器没有对恶意的用户输入进行安全处理就直接反射响应内容,导致恶意代码在浏览器中执行的一种XSS漏洞

代码:

const express = require('express');
const app = express();
const path = require('path');
const fs = require('fs');
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
app.use(express.static(path.resolve(__dirname,'public')));

app.get('/category',function (req,res){
    const { tag } = req.query;
    res.header('Content-Type','text/html;charset=utf-8');
    res.send(`tag is':${tag}`);
})

app.listen(5000,()=>console.log('server is runnning port 5000'));
const express = require('express');
const app = express();
const path = require('path');
const fs = require('fs');
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
app.use(express.static(path.resolve(__dirname,'public')));

app.get('/category',function (req,res){
    const { tag } = req.query;
    res.header('Content-Type','text/html;charset=utf-8');
    res.send(`tag is':${tag}`);
})

app.listen(5000,()=>console.log('server is runnning port 5000'));

存储型(持久型)

持久型XSS是利用将代码存储到漏洞服务器中,用户浏览相关被植入恶意代码代码的页面发起攻击。

注入流程:

  1. 将恶意脚本代码上传或者存储到漏洞服务器
  2. 服务器把恶意脚本保存到服务器
  3. 当正常用户访问服务器时,服务器会读取恶意数据并直接使用
  4. 服务器会返回含有恶意脚本的页面

存储型XSS示例代码

<html>
<body>
<div id="list"></div>
<form onsubmit="addUser(event)">
    <div >
        <label for="username">用户名</label>
        <input id="username" class="form-control" placeholder="用户名">
    </div>
    <div >
        <input type="submit">
    </div>
</form>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    function getData(){
        $.get('/api/users').then(res=>{
            let html = res.map(i=>(
                    ` <div>${i}</div> `
            )).join('');
            $('#list').html(html)
        })
    }
    getData();
    function addUser(event){
        event.preventDefault();
        const username = $('#username').val();
        if(!username) return;
        $.post('/api/users',{username}).then(data=>{
            getData();
            $('#username').val('');
        })
    }
</script>
</html>
<html>
<body>
<div id="list"></div>
<form onsubmit="addUser(event)">
    <div >
        <label for="username">用户名</label>
        <input id="username" class="form-control" placeholder="用户名">
    </div>
    <div >
        <input type="submit">
    </div>
</form>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    function getData(){
        $.get('/api/users').then(res=>{
            let html = res.map(i=>(
                    ` <div>${i}</div> `
            )).join('');
            $('#list').html(html)
        })
    }
    getData();
    function addUser(event){
        event.preventDefault();
        const username = $('#username').val();
        if(!username) return;
        $.post('/api/users',{username}).then(data=>{
            getData();
            $('#username').val('');
        })
    }
</script>
</html>
const express = require('express');
const app = express();
const path = require('path');
const fs = require('fs');
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:true}));
// app.use(bodyParser.json());

let users = ['vincent','candy','ethan'];
app.use(express.static(path.resolve(__dirname,'public')));

app.get('/users',function (req,res){
    res.send(users);
})
app.post('/users',function (req,res){
    const {username} = req.body;
    users.push(username)
    res.json(users);
})
app.listen(3000,()=>console.log('server is runnning port 3000'));
const express = require('express');
const app = express();
const path = require('path');
const fs = require('fs');
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:true}));
// app.use(bodyParser.json());

let users = ['vincent','candy','ethan'];
app.use(express.static(path.resolve(__dirname,'public')));

app.get('/users',function (req,res){
    res.send(users);
})
app.post('/users',function (req,res){
    const {username} = req.body;
    users.push(username)
    res.json(users);
})
app.listen(3000,()=>console.log('server is runnning port 3000'));

启动服务,打开localhost:3000可以看到运行的代码 img.png

现在来添加一个用户名 joel img_2.png

img_1.png

现在都可以正常的运行,因为输入的是不含特殊字符字符串,接下来输入一段字符串<script>alert(1)</script>;

img_3.png

立即有一个弹窗弹出,而且刚输入的<script>alert(1)</script>也没有显示出来;

img_4.png

并且users 已经把<script>alert(1)</script>添加进了。

img_5.png

到现在已经达到恶意脚本的录入到服务器中,用户每次请求该页面都会执行该恶意的内容;

img_6.png

其中的alert(1)可以替换成其他内容。如获取cookie等敏感信息。因此,需要对传入的数据进行转译处理。

DOM-Based型的XSS

特点: 不需要服务端支持,是由于DOM结构修改导致。基于浏览器DOM解析的攻击。

注入流程:

  1. 用户打开带有恶意的链接
  2. 浏览器在DOM解析的时候直接使用恶意数据
  3. 用户中招
  4. 常见的触发场景是在修改innerHTML outerHTML document.write的时候
<body>
    <h1>输入链接地址,然后点击按钮</h1>
    <div id="content"></div>
    <input type="text" id="link">
    <button onclick="setup()">设置</button>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        function setup() {
            // " onclick=alert(1) //
            let html = `<a href="${$('#link').val()}">点我</a>`;
            $('#content').html(html);
        }
    </script>
</body>
<body>
    <h1>输入链接地址,然后点击按钮</h1>
    <div id="content"></div>
    <input type="text" id="link">
    <button onclick="setup()">设置</button>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        function setup() {
            // " onclick=alert(1) //
            let html = `<a href="${$('#link').val()}">点我</a>`;
            $('#content').html(html);
        }
    </script>
</body>

Payload

实现XSS攻击的恶意脚本被叫做 XSS payload.

  • 窃取用户的cookie document.cookie
  • 识别用户浏览器 navigator.userAgent
  • 伪造请求 GET POST请求
  • XSS钓鱼 通过XSS向网页上注入钓鱼链接,让用户访问假冒的网站

如何防御XSS攻击

  • 基于特征的防御。XSS漏洞和著名的SQL注入漏洞一样,都是利用了Web页面的编写不完善,所以每一个漏洞所利用和针对的弱点都不尽相同。这就给XSS漏洞防御带来了困难,不可能以单一特征来概括所有XSS攻击。 传统的XSS防御在进行攻击鉴别时多采用特征匹配方式,主要是针对“javascript”这个关键字进行检索,但是这种鉴别不够灵活,凡是提交的信息中各有“javascript”时,就被硬性的被判定为XSS攻击。

  • 基于代码修改的防御。Web页面开发者在编写程序时往往会出现一些失误和漏洞,XSS攻击正是利用了失误和漏洞,因此一种比较理想的方法就是通过优化Web应用开发来减少漏洞,避免被攻击:1)用户向服务器上提交的信息要对URL和附带的的HTTP头、POST数据等进行查询,对不是规定格式、长度的内容进行过滤。2)实现Session标记(session tokens)、CAPTCHA系统或者HTTP引用头检查,以防功能被第三方网站所执行。3)确认接收的的内容被妥善的规范化,仅包含最小的、安全的Tag(没有javascript),去掉任何对远程内容的引用(尤其是样式表和javascript),使用HTTP only的cookie。

  • 客户端分层防御策略。客户端跨站脚本攻击的分层防御策略是基于独立分配线程和分层防御策略的安全模型。它建立在客户端(浏览器),这是它与其他模型最大的区别,之所以客户端安全性如此重要,客户端在接受服务器信息,选择性的执行相关内容。这样就可以使防御XSS攻击变得容易,该模型主要由三大部分组成:1)对每一个网页分配独立线程且分析资源消耗的“网页线程分析模块”;2)包含分层防御策略四个规则的用户输入分析模块;3)保存互联网上有关XSS恶意网站信息的XSS信息数据库。

  • XSS攻击主要是由程序漏洞造成的,要完全防止XSS安全漏洞主要依靠程序员较高的编程能力和安全意识,当然安全的软件开发流程及其他一些编程安全原则也可以大大减少XSS安全漏洞的发生。这些防范XSS漏洞原则包括:

    • 不信任用户提交的任何内容,对所有用户提交内容进行可靠的输入验证,包括对URL、查询关键字、HTTP头、REFER、POST数据等,仅接受指定长度范围内、采用适当格式、采用所预期的字符的内容提交,对其他的一律过滤。尽量采用POST而非GET提交表单;对“<”,“>”,“;”,“””等字符做过滤;任何内容输出到页面之前都必须加以en-code,避免不小心把htmltag显示出来。
    • 实现Session 标记(session tokens)、CAPTCHA(验证码)系统或者HTTP引用头检查,以防功能被第三方网站所执行,对于用户提交信息的中的img等link,检查是否有重定向回本站、不是真的图片等可疑操作。
    • cookie 防盗。避免直接在cookie中泄露用户隐私,例如email、密码,等等;通过使cookie和系统IP绑定来降低cookie泄露后的危险。这样攻击者得到的cookie没有实际价值,很难拿来直接进行重放攻击。
    • 确认接收的内容被妥善地规范化,仅包含最小的、安全的Tag(没有JavaScript),去掉任何对远程内容的引用(尤其是样式表和JavaScript),使用HTTPonly的cookie

参考链接:百度百科