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…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...

FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...