DOM 被劫持
文档对象模型(DOM
)充当着 HTML
和 JavaScript
之间的接口,搭建起静态内容与动态交互之间的桥梁,对现代 Web
开发而言,DOM
的作用不可或缺。
然而,DOM
也有一个致命的陷阱 —— DOM
劫持。DOM
劫持是指当 HTML
元素与全局 JavaScript
变量或函数产生冲突时,可能会导致 Web
应用程序出现不可预期的行为,甚至产生潜在的安全漏洞。
今天就可大家一起来聊聊 DOM
劫持的问题。
DOM 劫持是怎么发生的?
每个 HTML
元素都可以有一个唯一的 id
或 name
属性,方便在 JavaScript
中引用特定的元素。例如,下面的 HTML
按钮具有一个值为 "myButton"
的 id
属性:
<button id="myButton">Click Me!</button>
我们可以在 JavaScript
代码中使用此 ID
来操作按钮,例如,当点击时改变其文本:
document.getElementById('myButton').onclick = function() {this.textContent = 'Clicked!';
};
如果 HTML
元素的 id
或 name
属性与全局 JavaScript
变量或函数冲突会发生什么呢?
当浏览器加载 HTML
页面时,它会自动为 HTML DOM
中的每个 id
和 name
属性创建全局 JavaScript
变量。如果我们有一个名为 “myButton”
的 HTML
元素,浏览器会创建一个全局 JavaScript
变量 myButton
,引用该 HTML
元素。
现在,让我们考虑一个场景,其中我们声明了一个名为 myButton
的 JavaScript
函数:
function myButton() {// some code
}
但我们还有一个 id
或 name
为 “myButton”
的 HTML
元素。当页面加载时,浏览器的自动进程会引用 HTML
元素并覆盖 JavaScript
函数 myButton
。
<button id="myButton">Click Me!</button>console.log(myButton); // This will log the HTML button element, not the function
这个过程叫做 DOM
劫持,它可能会引发不可预测的行为和安全漏洞。如果攻击者能控制这些属性,他们可能有能力向网页注入恶意代码,从而引发包括跨站脚本(XSS
)在内的安全问题。
为了说明这一点,让我们考虑以下情景:
Enter your name: <input id="username" type="text">
<button onclick="greet()">Greet</button>function greet() {var username = document.getElementById('username').value;alert(`Hello ${username}`);
}
攻击者可以输入类似 <img id='alert' src=x onerror='alert(1)'>
的内容,创建一个 'id'
为 'alert'
的新 HTML
组件。该组件会破坏 JavaScript
中的正常 alert 功能。下次网站尝试使用此功能时,它将无法正常工作,甚至可能运行恶意代码。
我们想象现在有一个带有用户反馈功能的基本 Web
应用程序。用户输入自己的姓名和反馈消息,然后提交。页面显示反馈:
html:
<h2>Feedback Form</h2>
<form><label for="name">Name:</label><br><input type="text" id="name" name="name"><br><label for="feedback">Feedback:</label><br><textarea id="feedback" name="feedback"></textarea><br><input type="submit" value="Submit">
</form><div id="feedbackDisplay"></div>
JavaScript:
document.querySelector('form').onsubmit = function(event) {event.preventDefault();let name = document.getElementById('name').value;let feedback = document.getElementById('feedback').value;let feedbackElement = document.getElementById('feedbackDisplay');feedbackElement.innerHTML = `<p><b>${name}</b>: ${feedback}</p>`;
};
这段代码会获取用户的姓名和反馈,并将其显示在 FeedbackDisplay div
内的段落元素中。
攻击者可以通过在反馈表单中提交一段 HTML
来利用此代码。例如,如果他们在名称字段中输入以下代码并提交表单,则反馈显示区域就会被 Script
替换:
<script id="feedbackDisplay">window.location.href='http://conardli.top';</script>
当表单尝试显示下一条反馈时,就会执行脚本,将用户重定向到恶意网站。这是 DOM 劫持造成严重后果的一个例子 —— 攻击者可以控制用户的浏览器,从而窃取敏感数据或安装恶意软件。
缓解 DOM 劫持的安全编码实践
通过更深入地了解这些漏洞,我们可以继续采取一些最佳实践来减轻 DOM 劫持的风险。
正确定义变量和函数的作用域
DOM
劫持的最常见原因之一是滥用 JavaScript
中的全局作用域。
通过在特定的作用域范围内定义变量和函数,我们可以限制对该范围或任何嵌套范围的覆盖,并最大限度地减少潜在的冲突。
我们来用 JavaScript
的作用域规则并重构前面的示例来展示如何做到这一点:
(function() {// All variables and functions are now in this function's scopeconst form = document.querySelector('form');const feedbackElement = document.getElementById('feedbackDisplay');form.onsubmit = function(event) {event.preventDefault();const name = document.getElementById('name').value;const feedback = document.getElementById('feedback').value;// Sanitize user inputname = DOMPurify.sanitize(name);feedback = DOMPurify.sanitize(feedback);const newFeedback = document.createElement('p');newFeedback.textContent = `${name}: ${feedback}`;feedbackElement.appendChild(newFeedback);};
})();
首先我们使用了 DOMPurify
来对上述代码块中的用户输入进行清理。
在此版本的代码中,我们将所有内容都包含在立即调用函数表达式 (IIFE
) 中,这会创建一个新作用域。form
和 FeedbackElement
变量以及分配给 onsubmit
事件处理程序的函数不在全局作用域内,因此它们不能被劫持。
使用唯一标识符
确保网页上的每个元素都有唯一的 id 可以降低无意中覆盖重要函数或变量的风险。另外,避免使用通用名称或可能与全局 JavaScript
对象或函数冲突的名称。
避免全局命名空间污染
保持全局命名空间干净是编写安全 JavaScript
的一个重要方面。全局作用域中的变量和函数越多,DOM劫持的风险就越大。使用 JavaScript
的函数作用域或 ES6
的块作用域来保留变量和函数。这是使用后者的示例:
let form = document.querySelector('form');let feedbackElement = document.getElementById('feedbackDisplay');form.onsubmit = function(event) {event.preventDefault();let name = document.getElementById('name').value;let feedback = document.getElementById('feedback').value;// Sanitize user inputname = DOMPurify.sanitize(name);feedback = DOMPurify.sanitize(feedback);let newFeedback = document.createElement('p');newFeedback.textContent = `${name}: ${feedback}`;feedbackElement.appendChild(newFeedback);};
在这段代码中,我们使用块(由 {}
定义)来创建新作用域。所有变量和函数现在都限制在该块中,并且不在全局作用域内。
正确使用 JavaScript 特性
现代 JavaScript
提供了一些有助于最大限度地缓解 DOM 劫持的风险。特别是 ES6
中引入的 let
和 const
关键字提供了对声明变量的更多控制。
在以前,我们使用 var
关键字声明 JavaScript
变量。var
有一些怪癖,其中之一是就它没有块作用域,只有函数作用域和全局作用域。这意味着用 var
声明的变量可以在声明它的块之外访问和覆盖。
另一方面,let
和 const
都具有块作用域,这意味着它们只能在声明它们的块内访问。这一特性通常使它们成为变量声明的更好选择,因为它限制了覆盖变量的可能性。
我们还可以使用 const
来声明常量 — 分配它们后我们无法更改的值。它们可以防止重要的变量被意外覆盖。
const form = document.querySelector('form');const feedbackElement = document.getElementById('feedbackDisplay');form.onsubmit = function(event) {event.preventDefault();const name = document.getElementById('name').value;const feedback = document.getElementById('feedback').value;// Sanitize user inputname = DOMPurify.sanitize(name);feedback = DOMPurify.sanitize(feedback);const newFeedback = document.createElement('p');newFeedback.textContent = `${name}: ${feedback}`;feedbackElement.appendChild(newFeedback);};
在此代码中,我们将所有 var
的使用替换为 const
。我们将所有变量限制在声明它们的块中,并且常量不能被覆盖。
但是 ,使用 let
和 const
并不能完全消除 DOM
劫持的风险,但这种做法仍然是安全编码的一个关键方面。
使用 Devtools 发现潜在的 DOM 劫持风险
例如 Chrome
或 Firefox
中的浏览器开发者工具,也是探测 DOM
劫持漏洞的强大助手。
最简单的方法,我们直接打开 Devtools
。
然后在控制台输入 window
,这里面包含了网站全局作用域下所有的全局变量和函数。
然后我们检查下是否有任何看起来不合适的变量,尤其是那些与 HTML
元素 id
或 name
同名的变量。
通过 Elements
选项卡,编辑页面的 HTML
来操控 DOM
并测试潜在的漏洞。例如,添加一个 id
与全局变量或函数相匹配的元素,看看是否会被覆写。
相关文章:
DOM 被劫持
文档对象模型(DOM)充当着 HTML 和 JavaScript 之间的接口,搭建起静态内容与动态交互之间的桥梁,对现代 Web 开发而言,DOM 的作用不可或缺。 然而,DOM 也有一个致命的陷阱 —— DOM 劫持。DOM 劫持是指当 H…...

PIG框架学习2——资源服务器的配置详解
一、前言 1、pig资源服务器的配置 Spring Security oauth2相关的依赖是在pigx-common-security模块中引入的,其他模块需要进行token鉴权的,需要在微服务中引入pigx-common-security模块的依赖,从而间接引入相关的Spring security oauth2依赖…...
vue+element ui实现图片上传并拖拽进行图片排序
用到的技术栈: vue2element Uivue-dragging 如何使用: 第一步: 安装 npm install awe-dnd --save第二步: 引入 main.js 文件 // 引入组件 import VueDND from awe-dnd // 添加至全局 Vue.use(VueDND)具体项目代码 <el-form-item label"封面…...

国产服务器 BIOS下组建RADI不同RAID卡-超详细
国产服务器 长城 组建Raid的方法 说明 大多数国产服务器通用型服务器进入BIOS的都是按DEL键。 9361RAID卡组建方法 在服务器启动过程中,按下DEL键进入BIOS界面。 进入设备管理器,选择AVAGO MegaRAID页签。 3. 进入RAID卡设备,选择Main Me…...

UE4 4.21-4.27使用编辑器蓝图EditorBlueprint方法
在UE4 4.21中,编辑器蓝图(Editor Blueprint)是一个强大的工具,允许开发者扩展和自定义Unreal编辑器的功能。通过编辑器蓝图,我们可以创建自定义的工具和功能,以优化开发流程。 本教程将指导您如何在UE4 4.…...

105、Zero-1-to-3: Zero-shot One Image to 3D Object
简介 官网 使用合成数据集来学习相对摄像机视点的控制,这允许在指定的摄像机变换下生成相同对象的新图像,用于从单个图像进行三维重建的任务。 实现流程 输入图像 x ∈ R H W 3 x \in \R^{H \times W \times 3} x∈RHW3,所需视点的相…...

scala 安装和创建项目
Scala,一种可随您扩展的编程语言:从小型脚本到大型多平台应用程序。Scala不是Java的扩展,但它完全可以与Java互操作。在编译时,Scala文件将转换为Java字节码并在JVM(Java虚拟机)上运行。Scala被设计成面向对…...

Python办公自动化 – 自动化文本翻译和Oracle数据库操作
Python办公自动化 – 自动化文本翻译和Oracle数据库操作 以下是往期的文章目录,需要可以查看哦。 Python办公自动化 – Excel和Word的操作运用 Python办公自动化 – Python发送电子邮件和Outlook的集成 Python办公自动化 – 对PDF文档和PPT文档的处理 Python办公自…...

如何在Win10电脑接收苹果手机日程提醒呢?
有很多小伙伴手机使用的是iPhone苹果手机,但办公电脑使用的win10系统的电脑,这时候如果想要在win10电脑上同步接收苹果手机上设置的日程提醒,该怎么操作呢?如何在win10电脑接收苹果手机日程提醒呢? 如果你设置的日程提…...
227.【2023年华为OD机试真题(C卷)】小明找位置(二分查找-JavaPythonC++JS实现)
🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目-小明找位置二.解题思路三.题解代码Python题解代…...

【现代密码学】笔记3.4-3.7--构造安全加密方案、CPA安全、CCA安全 《introduction to modern cryphtography》
【现代密码学】笔记3.4-3.7--构造安全加密方案、CPA安全、CCA安全 《introduction to modern cryphtography》 写在最前面私钥加密与伪随机性 第二部分流加密与CPA多重加密 CPA安全加密方案CPA安全实验、预言机访问(oracle access) 操作模式伪随机函数PR…...
服务器带宽有什么用? 带宽不足怎么办?
服务器带宽是指服务器能够接收和传输数据的速率,通常以每秒传输的数据量来衡量。它是支持特定应用服务器网络和因特网(Internet)访问的单一网络线路,对网络速度、响应时间、应用程序处理速度等方面都有影响。 服务器带宽有什么作…...

Alphafold2蛋白质结构预测AI工作站配置推荐
AlphaFold2计算特点 蛋白质三维结构预测是一项计算量非常巨大的任务,科学家多年的探索研究,形成了X射线晶体学法、核磁共振法、冷冻电镜等。 2021年底,谷歌的DeepMind团队的采用人工智能方法的AlphaFold2算法在生物界引起了极大的轰动…...

如何让ArcGIS Pro启动显示空白页面
刚接触ArcGIS Pro的你是否会觉得在操作上有那么一些不习惯,从一开始软件启动就发现和ArcGIS差距很大:丰富的欢迎页面,加上默认加载的地图让你眼花缭乱,这里教你如何去掉这些繁杂的内容,还你一个干净的启动页面。 跳过…...
超市账单管理系统产品数据新增Servlet实现
超市账单管理系统产品数据新增Servlet实现 package com.test.controller; import java.io.IOException; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import ja…...

计算机组成原理之计算机硬件发展和计算机系统的组成
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…...

《JVM由浅入深学习【七】 2024-01-11》JVM由简入深学习提升分享
亲爱的读者们,欢迎来到本篇博客,这是JVM第七次分享,下面是七个JVM常用常面的分享,请笑纳 目录 1. 几个与JVM 内存相关的核心参数2.如何计算一个对象的大小3.堆为什么要分为新生代和老年代4.JVM堆的年轻代为什么要有两个 Survivor…...

Golang leetcode142 环形链表 暴力map 快慢指针法
文章目录 环形链表 leetcode142暴力遍历 map哈希记录快慢指针法 环形链表 leetcode142 该题目要求找到入环的第一个节点 我们可以通过map进行记录,没到新的节点查询是否经过原有节点 入环节点,上两个节点的next相同 若有入环节点,则一定能检…...

基于java,springboot的论旅游管理系统设计与实现
环境以及简介 基于java,springboot的论旅游管理系统设计与实现,Java项目,SpringBoot项目,含开发文档,源码,数据库以及ppt 源码下载 环境配置: 框架:springboot JDK版本:JDK1.8 服…...

掌握视频节奏,玩转剪辑艺术!,轻松调整视频播放速度与秒数的技巧大揭秘
你是否经常觉得视频播放得太快或太慢,无法满足你的观看需求?或者想要控制视频的长度,却不知道该如何下手?今天,我们将为你揭秘几种简单又实用的方法,让你轻松调整视频的播放速度和秒数! 首先&a…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...