导航我们都知道,高德地图对吧,我们搜索一个地点,它告诉我们如何到达。对于网站来说,导航是帮助用户到达用户想去的地方(网址)
在 Electron
中也是一样,凡是离开当前地址的操作都可以算作是跳转和导航,最常见的是点击了某个链接,之后我们进入到链接中,点击了某个功能,进入到该功能模块中
对于应用程序来说,通常不需要在页面中渲染第三方的网页,尤其是在 Electron
中,加载第三方页面可能会导致用户被远程命令执行,因此官方推荐禁用或限制网页跳转
参考文章
公众号开启了留言功能,欢迎大家留言讨论~
这篇文章也提供了 PDF
版本及 Github
,见文末
0x01 简介
0x02 效果展示
0x03 官方安全建议
0x04 哪些行为会导致网页跳转
1. a 标签
2. 表单提交
3. meta 标签自动刷新
4. iframe 加载
5. window.location
6. window.history
7. window.open
8. window.top
0x05 漏洞案例
0x06 总结
0x07 PDF 版 & Github
往期文章
点击链接后
官方建议是禁用或限制网页跳转,所谓的限制也就是说选择性地网页跳转,例如允许跳转到自己以及子域名等可控范围内的内容,官方给出代码如下
`const { URL } = require('url') const { app } = require('electron') app.on('web-contents-created', (event, contents) => { contents.on('will-navigate', (event, navigationUrl) => { const parsedUrl = new URL(navigationUrl) if (parsedUrl.origin !== 'https://example.com') { event.preventDefault() } }) }) `
官方还专门强调,建议使用Node的解析器来处理URL, 简单的字符串比较有时会出错
既然有了防御代码,我们便可以测试一下,到底哪些行为会进行网页跳转
点击 a
标签后,成功输出 URL
对象,其中完整内容为
`URL { href: 'https://www.baidu.com/robots.txt', origin: 'https://www.baidu.com', protocol: 'https:', username: '', password: '', host: 'www.baidu.com', hostname: 'www.baidu.com', port: '', pathname: '/robots.txt', search: '', searchParams: URLSearchParams {}, hash: '' } `
其中 origin
就是我们所谓的同源策略里的源,它包含协议、主机名、端口号
所以官方的防御代码就是验证是不是与 https://example.com
同源的,非同源则直接组织
`<form action="https://example.com/submit" method="POST"> <!-- 表单内容 --> <input type="text" name="username"> <button type="submit">提交</button> </form> `
上一节新窗口创建的案例,当然这里 target
设置什么无所谓,我们直接去掉了,关键是 action
属性,这个属性的值造成跳转
出发了跳转和导航事件
`<meta http-equiv="refresh" content="5;url=https://example.com"> `
5 秒后
成功触发监听
点击按钮
创建一个 iframe
并没有引起主进程的跳转和导航事件,我们修改代码,测试一下按按钮修改 iframe
的 src
属性
点击按钮
看来 iframe
的src
修改不会触发主进程的跳转与导航事件
iframe
加载的内容中通过 window.top.location
修改顶层窗口的 URL
5 秒后
触发导航事件
Window.location
只读属性返回一个 Location
对象,其中包含有关文档当前位置的信息
尽管 Window.location
是一个只读 Location
对象,你仍然可以将字符串赋值给它。这意味着可以在大多数情况下像字符串一样处理 location
——location = 'http://www.example.com'
——与 location.href = 'http://www.example.com'
等价。
在上一篇文章中,我们介绍了通过 window.open().location
绕过安全限制的手法,其中 location
或者说 location.href
的值就是要导航去的位置
返回当前页面的完整URL字符串,也可以用来设置新的URL以导航到其他页面
`window.location.href = "https://www.baidu.com/" `
5秒后
触发导航事件
导航到一个新页面
`window.location.assign("https://www.mozilla.org"); `
5秒后
触发导航事件
重新加载当前页面
`window.location.reload(); `
5秒后
触发导航事件
替换当前页面的 URL
`window.location.replace('https://example.com') `
5秒后
触发导航事件
在 url 后面加上搜索字符串
`window.location.search = "test" `
5 秒后
属性较多,基本上都是 URL 的一部分,如果修改也会导航事件
href: 返回当前页面的完整URL字符串,也可以用来设置新的URL以导航到其他页面。
protocol: 返回当前URL的协议部分,例如 http:
或 https:
host: 返回当前URL的主机名(域名+端口),例如 example.com:8080
hostname: 返回当前URL的主机名(不包括端口),例如 example.com
port: 返回当前URL的端口号,如果省略则默认端口不会显示
pathname: 返回当前URL的路径部分,从根目录开始,例如 /path/to/page.html
search: 返回URL的查询字符串部分,从问号 ?
开始,例如 ?key=value&anotherKey=anotherValue
hash: 返回URL的哈希片段标识符(锚点),从井号 "#" 开始,例如 #section1
origin: 返回URL的起源部分,由协议、主机名和端口组成,例如 http://example.com:80
历史记录属性可以通过其以下几个方法进行导航
back(): 导航到历史记录中的上一个页面。
forward(): 导航到历史记录中的下一个页面。
go(delta): 依据delta
参数向前或向后导航。正值表示向前,负值表示向后,0通常不会产生导航效果但可能刷新页面。
这就相当于浏览器的前后按钮了
这部分上一篇文章新窗口创建的部分已经介绍了,会触发导航事件
window.top
是一个JavaScript对象属性,它引用了当前窗口或框架的最顶层窗口(即最高层级的浏览器窗口)
对于没有上层窗口的渲染进程, window === window.top
,所以修改 window.top.location
就可以修改当前页面的 url
对于 iframe
等子窗口,使用 window.top.location
可以修改顶层窗口的 URL
Masato Kinugawa
曾经在 Discord RCE
的过程中利用了一个导航的漏洞 —— CVE-2020-15174
在 iframe
中,如果设置 top.location
的地址和 iframe
的地址不同源,则不会触发 will-navigate
事件,即导航事件,这显然是一个 bug
网页跳转和导航的触发方法很多,但最终效果几乎都是一致的,就是在当前窗口或新窗口加载页面,在较新的版本中, will-navigate
能够有效地监听和阻断导航行为,开发者可以根据实际情况,考虑禁用或者限制导航行为
PDF
版
Github
有态度,不苟同