XSS ..

Web安全中的XSS攻击详细教学,Xss-Labs靶场通关全教程(建议收藏) - 白小雨 - 博客园跨站脚本攻击(XSS)主要是攻击者通过注入恶意脚本到网页中,当用户访问该页面时,恶意脚本会在用户的浏览器中执行,从而可能导致数据被篡改、用户信息泄露等问题。为了防止 XSS 攻击导致的数据篡改,可以从输入验证与过滤、输出编码、设置 CSP、HttpOnly 等方面着手,以下是详细介绍:

输入验证与过滤

  • 原理:在数据进入应用程序之前,对用户输入进行严格的验证和过滤,只允许合法的字符和格式通过。

  • 示例:在使用 JavaScript 编写表单验证时,可使用正则表达式来验证用户输入是否符合预期。

    function validateInput(input) {
    // 只允许字母和数字
    const regex = /^[a-zA-Z0-9]+$/;
    return regex.test(input);
    }

    const userInput = document.getElementById('userInput').value;
    if (validateInput(userInput)) {
    // 处理合法输入
    } else {
    // 提示用户输入不合法
    }

输出编码

  • 原理:在将数据输出到 HTML、JavaScript、CSS 等环境中时,对特殊字符进行编码,将其转换为 HTML 实体或其他安全的表示形式,防止恶意脚本的注入。

  • 示例 :在 Node.js 中使用 he 库对输出进行 HTML 编码。

    const he = require('he');
    const userInput = '<script>alert("XSS")</script>';
    const encodedInput = he.encode(userInput);
    // 输出编码后的内容,如 <script>alert("XSS")</script>
    console.log(encodedInput);

设置内容安全策略(CSP)

  • 原理:通过设置 HTTP 头信息,指定页面可以加载哪些资源(如脚本、样式表、图片等),从而限制恶意脚本的加载和执行。

  • 示例:在 Node.js 的 Express 框架中设置 CSP 头信息。

    const express = require('express');
    const app = express();

    app.use((req, res, next) => {
    res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self'");
    next();
    });

    app.get('/', (req, res) => {
    res.send('Hello, World!');
    });

    const port = 3000;
    app.listen(port, () => {
    console.log(Server is running on port ${port});
    });

使用 HttpOnly 属性

  • 原理 :对于存储敏感信息的 Cookie,设置 HttpOnly 属性,这样 JavaScript 脚本就无法访问这些 Cookie,从而防止攻击者通过 XSS 攻击窃取或篡改 Cookie 中的数据。

  • 示例 :在 Node.js 的 Express 框架中设置带有 HttpOnly 属性的 Cookie。

    const express = require('express');
    const app = express();

    app.get('/', (req, res) => {
    res.cookie('session_id', '123456', { httpOnly: true });
    res.send('Cookie has been set');
    });

    const port = 3000;
    app.listen(port, () => {
    console.log(Server is running on port ${port});
    });

避免内联事件和内联脚本

  • 原理 :内联事件(如 onclickonload)和内联脚本容易受到 XSS 攻击,应尽量避免使用。可以通过分离 HTML、CSS 和 JavaScript 代码,使用事件委托等方式来处理事件。

  • 示例:不推荐的内联事件写法:

    <button onclick="alert('Hello')">点击我</button>

推荐的事件委托写法:

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
</head>

<body>
    <button id="myButton">点击我</button>
    <script>
        const button = document.getElementById('myButton');
        button.addEventListener('click', () => {
            alert('Hello');
        });
    </script>
</body>

</html>

定期更新和修复漏洞

  • 原理:及时更新使用的框架、库和服务器软件,修复已知的安全漏洞,减少被攻击的风险。同时,对应用程序进行定期的安全审计和漏洞扫描,及时发现和处理潜在的安全问题。

在处理潜在的不信任输入时,直接使用 innerHTML 是非常危险的,因为它可以导致跨站脚本攻击(XSS)。当您将不受信任的数据插入到网页中时,如果使用了 innerHTML,那么这段数据可能会包含恶意脚本,这些脚本会在用户的浏览器上执行。

例如,如果你直接从用户输入获取数据并将其赋值给 innerHTML,如下所示:

复制代码
const userInput = "<img src='x' onerror='alert(\"XSS\")'>";
someElement.innerHTML = userInput;

在这种情况下,用户的输入包含了恶意脚本,它会创建一个带有错误图片链接的 <img> 标签,并且当加载图像失败时触发 onerror 事件,从而执行 JavaScript 警告框。这种行为就是 XSS 攻击的一个简单例子。

为了避免这种情况,你应该尽量避免直接使用 innerHTML 来插入不信任的内容。如果必须使用,应该确保对内容进行适当的转义或清理,以去除任何可能的脚本元素或其他危险代码。更安全的选择是使用文本显示方法如 textContent 或者 innerText 来显示不信任的内容,因为它们不会解析 HTML,因此不会执行其中的脚本。

另外,对于一些特定场景,比如需要允许某些格式化但不允许脚本执行,可以考虑使用库如 DOMPurify 对输入进行清理,这样可以安全地移除潜在的有害部分但仍保留一定的富文本格式。例如:

复制代码
import DOMPurify from 'dompurify';

const cleanUserInput = DOMPurify.sanitize(userInput);
someElement.innerHTML = cleanUserInput;

总之,在处理用户输入时务必小心谨慎,尤其是在将其插入到页面中时,应采取一切必要措施防止 XSS 攻击。

1. 输入验证

使用正则表达式对用户输入进行验证,只允许特定字符通过,避免恶意脚本注入。

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>输入验证防止 XSS</title>
</head>

<body>
    <input type="text" id="userInput" placeholder="请输入内容">
    <button id="submitButton">提交</button>
    <div id="output"></div>

    <script>
        function validateInput(input) {
            // 只允许字母、数字、空格和常见标点符号
            const regex = /^[a-zA-Z0-9\s.,!?]+$/;
            return regex.test(input);
        }

        const inputElement = document.getElementById('userInput');
        const submitButton = document.getElementById('submitButton');
        const outputElement = document.getElementById('output');

        submitButton.addEventListener('click', function () {
            const userInput = inputElement.value;
            if (validateInput(userInput)) {
                // 处理合法输入
                outputElement.textContent = `你输入的内容是: ${userInput}`;
            } else {
                outputElement.textContent = '输入包含非法字符,请重新输入。';
            }
        });
    </script>
</body>

</html>

在这个示例中,validateInput 函数使用正则表达式对用户输入进行验证,确保输入只包含字母、数字、空格和常见标点符号。如果输入合法,将其显示在页面上;否则,给出错误提示。

2. 输出编码

将用户输入的内容进行 HTML 实体编码,避免浏览器将其解析为 HTML 标签或脚本。可以使用 DOMPurify 库来实现。首先需要引入 DOMPurify 库,你可以通过 CDN 引入:

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>输出编码防止 XSS</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.11/purify.min.js"></script>
</head>

<body>
    <input type="text" id="userInput" placeholder="请输入内容">
    <button id="submitButton">提交</button>
    <div id="output"></div>

    <script>
        const inputElement = document.getElementById('userInput');
        const submitButton = document.getElementById('submitButton');
        const outputElement = document.getElementById('output');

        submitButton.addEventListener('click', function () {
            const userInput = inputElement.value;
            // 使用 DOMPurify 进行净化
            const clean = DOMPurify.sanitize(userInput);
            outputElement.innerHTML = clean;
        });
    </script>
</body>

</html>

在这个示例中,当用户点击提交按钮时,使用 DOMPurify.sanitize 方法对用户输入进行净化,将其中的恶意脚本等危险内容过滤掉,然后将净化后的内容插入到页面中。

3. 避免使用内联事件和内联脚本

内联事件(如 onclickonload)和内联脚本容易受到 XSS 攻击,应尽量避免使用。可以通过事件委托等方式来处理事件。

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>避免内联事件防止 XSS</title>
</head>

<body>
    <button id="myButton">点击我</button>
    <div id="output"></div>

    <script>
        const button = document.getElementById('myButton');
        const outputElement = document.getElementById('output');

        button.addEventListener('click', function () {
            outputElement.textContent = '按钮被点击了';
        });
    </script>
</body>

</html>

在这个示例中,使用 addEventListener 方法为按钮添加点击事件,而不是使用内联的 onclick 事件,这样可以避免潜在的 XSS 风险。

4. 使用 textContent 而不是 innerHTML

当需要向页面插入文本内容时,使用 textContent 而不是 innerHTML,因为 textContent 会将内容作为纯文本处理,不会解析其中的 HTML 标签。

复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>使用 textContent 防止 XSS</title>
</head>

<body>
    <input type="text" id="userInput" placeholder="请输入内容">
    <button id="submitButton">提交</button>
    <div id="output"></div>

    <script>
        const inputElement = document.getElementById('userInput');
        const submitButton = document.getElementById('submitButton');
        const outputElement = document.getElementById('output');

        submitButton.addEventListener('click', function () {
            const userInput = inputElement.value;
            // 使用 textContent 插入内容
            outputElement.textContent = userInput;
        });
    </script>
</body>

</html>

在这个示例中,使用 textContent 将用户输入的内容插入到页面中,确保内容以纯文本形式显示,避免 HTML 标签和脚本的执行。

相关推荐
恋猫de小郭37 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端