当前位置: 首页 > news >正文

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);
// 输出编码后的内容,如 &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;
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 标签和脚本的执行。

相关文章:

  • K8S有状态服务部署(MySQL、Redis、ES、RabbitMQ、Nacos、ZipKin、Sentinel)
  • K8S使用--dry-run输出资源模版和兼容性测试
  • Eigen矩阵的平移,旋转,缩放
  • 【SpringBoot教程】SpringBoot自定义注解与AOP实现切面日志
  • 深入解析二维矩阵搜索:LeetCode 74与240题的两种高效解法对比
  • C语言 指针(7)
  • 【工具变量】数字人民币试点城市DID(2007-2024年)
  • 【心海资源】0U攻击工具|一键模仿地址生成+余额归集+靓号生成系统
  • 神经网络:节点、隐藏层与非线性学习
  • Ubuntu 系统详解
  • Unable to determine the device handle for GPU0000:82:00.0: Unknown Error
  • 知乎前端面试题及参考答案
  • 用于备份的git版本管理指令
  • DC-DC降压型开关电源(Buck Converter)设计中,开关频率(f sw​ )、滤波电感(L)和滤波电容(C out​ )的关系和取舍
  • JDBC实现--保姆级教程~
  • 【东枫科技】代理英伟达产品:智能网卡
  • 【东枫科技】代理英伟达产品:交换机系统
  • Mysql group by 用法
  • 安装篇--CentOS 7 虚拟机安装
  • C++学习之路,从0到精通的征途:stack_queue的模拟实现及deque原理介绍
  • 山东莒县农商银行去年收入、利润下降,资本充足率等指标增长
  • 长和获准出售巴拿马运河港口以外的港口?外交部:该报道没有依据
  • 世界羽联主席巴达玛:中国组织赛事的能力无与伦比
  • 马丽称不会与沈腾终止合作,“他是我的恩人,也是我的贵人”
  • 特朗普考虑任命副幕僚长米勒任国安顾问,曾策划驱逐移民行动
  • 巴菲特股东大会精华版:批评拿贸易当武器,宣布年底交班