@grant为none时,使用unsafeWindow的YouTube快捷键Greasemonkey脚本是否安全?
关于YouTube快捷键脚本的安全问题说明
先把几个容易绕混的概念掰清楚
- 你现在脚本配了
@grant none,本质上根本不存在“额外安全权限被窃取”的问题。这个模式下脚本是直接注入到页面的主JS执行上下文跑的,所有能做的操作和YouTube自己写的原生JS完全没区别,本身就没有比普通页面JS更高的权限,自然也没有什么可以被恶意页面偷的“专属能力”。 - 官方反复提醒慎用
unsafeWindow,针对的是脚本开启了专属特权API的场景:当你给脚本加了@grant GM_xxx类的权限时,脚本会被丢到隔离沙箱里运行,这时候unsafeWindow是沙箱开的一个和页面主世界通信的桥。如果不小心把沙箱里的特权API引用通过这个桥漏出去,页面的恶意JS就能拿到本来只有脚本才能用的跨域请求、本地存储读写这类高权限能力,这才是所谓安全风险的核心来源。 - 你之前看到的“只要@grant设为none就安全”的说法,逻辑上是通的——因为@grant none模式下根本没有可被窃取的特权,自然也不存在这类攻击面。但你可能没意识到,这个场景下你写的
unsafeWindow其实是个根本不存在的变量。
你当前脚本的实际问题
根本不是什么安全漏洞,是这代码在@grant none配置下压根跑不通:
@grant none模式下,脚本和页面是同一个执行上下文,油猴的宿主环境根本不会给你注入unsafeWindow这个全局变量,你代码里所有用到unsafeWindow的行,跑起来就会直接抛ReferenceError: unsafeWindow is not defined的错,根本执行不到控制音量的逻辑。
无额外风险的稳妥写法
直接把所有unsafeWindow替换成原生的window、documentAPI就行,完全不需要借助unsafeWindow就能拿到页面的播放器对象,还能顺便修几个原来代码的小问题:
// ==UserScript== // @name Custom Youtube Hotkeys // @version 1 // @include https://www.youtube.com/watch* // @grant none // ==/UserScript== // 用addEventListener绑定事件,不会覆盖页面原本的按键逻辑 window.addEventListener('keypress', function(event) { // 输入框聚焦时跳过,不干扰搜索栏输入 if (document.activeElement.tagName === "INPUT") return; try { // 触发时再取播放器对象,避免页面动态加载元素时拿不到引用 const player = document.getElementById("movie_player"); if (!player) return; // 加个音量上下限,避免超范围触发播放器报错 if (event.keyCode == 120) { player.setVolume(Math.min(100, player.getVolume() + 5)); } else if (event.keyCode == 122) { player.setVolume(Math.max(0, player.getVolume() - 5)); } } catch(err) { console.log(err.message); } });
这种写法的安全等级和页面原生JS完全一致,不会引入任何额外攻击面,也不存在unsafeWindow带来的潜在权限泄露风险:
- 没有调用任何油猴专属的特权API
- 没有跨上下文的引用桥
- 所有操作都是页面原生JS本来就有权限执行的DOM操作和对象方法调用
什么时候才需要真的担心unsafeWindow的风险
只有当你后续给脚本加了@grant GM_*类的专属权限时,才需要绷紧安全这根弦:这时候脚本跑在隔离沙箱里,千万别把沙箱内部的特权API引用直接通过unsafeWindow暴露给页面上下文,否则就会触发官方提醒的安全问题。如果全程保持@grant none,根本不需要考虑这类风险。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

