├── logo.png ├── 2014.md ├── README.md ├── 2017.md ├── 2016.md ├── 2015.md └── 2018.md /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtherDream/web-frontend-magic/HEAD/logo.png -------------------------------------------------------------------------------- /2014.md: -------------------------------------------------------------------------------- 1 | # 2014-12-3 2 | 3 | ```js 4 | 1767707668033969..toString(36) // "helloworld" 5 | ``` 6 | 7 | --- 8 | 9 | 卖萌的语法~ 10 | 11 | ```js 12 | 0.==.0 13 | ``` 14 | 15 | 16 | # 2014-11-13 17 | 18 | Hack 小技巧:检测 console 是否被打开 19 | 20 | Demo: https://www.etherdream.com/FunnyScript/console_detect/ 21 | 22 | ![image](https://user-images.githubusercontent.com/1072787/69052258-93f9e000-0a41-11ea-82df-3434d694248a.png) 23 | 24 | ![image](https://user-images.githubusercontent.com/1072787/69052263-95c3a380-0a41-11ea-9e39-a2d5a72a8400.png) 25 | 26 | 发现有程序猿在调试,哥就封了它~ 27 | 28 | 29 | 30 | # 2014-8-16 31 | 32 | 最新原创: 《HttpOnly Cookie 隐私嗅探》 33 | 34 | https://fex.baidu.com/blog/2014/08/sensitive-data-sniffer/ 35 | 36 | 37 | 38 | # 2014-6-20 39 | 40 | 《XSS 前端防火墙》系列 41 | 42 | ![image](https://user-images.githubusercontent.com/1072787/69052455-08348380-0a42-11ea-8859-f527d728445b.png) 43 | 44 | https://fex.baidu.com/blog/2014/06/xss-frontend-firewall-1/ 45 | 46 | https://fex.baidu.com/blog/2014/06/xss-frontend-firewall-2/ 47 | 48 | https://fex.baidu.com/blog/2014/06/xss-frontend-firewall-3/ 49 | 50 | https://fex.baidu.com/blog/2014/06/xss-frontend-firewall-4/ 51 | 52 | https://fex.baidu.com/blog/2014/06/xss-frontend-firewall-5/ 53 | 54 | Demo: https://www.etherdream.com/FunnyScript/csp/battle/ 55 | 56 | > 该项目除了监控 XSS 之外,还可用于运营商/浏览器插件的流量劫持监控。过些时候开源~ 57 | 58 | 59 | # 2014 60 | 61 | 微博账号 @EtherDream 发布的已全部在此,之后更新在其他论坛发布的... 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web 前端黑魔法 2 | 3 | ![](logo.png) 4 | 5 | 收集整理过去发表的 #前端黑魔法# 话题。 6 | 7 | 在此怀念和 [@zswang](https://github.com/zswang) 交流探讨前端黑魔法的时光。 8 | 9 | 10 | # 2019 11 | 12 | ## HTTP 缓存更新 13 | 14 | 使用 fetch API 可更新 HTTP 缓存数据: 15 | 16 | ```js 17 | fetch(url, { 18 | cache: 'no-cache', 19 | }) 20 | ``` 21 | 22 | 设置 `cache` 选项为 `no-cache` 时,浏览器无视本地 HTTP 缓存,强制发起请求,并将最新内容覆盖已有缓存。 23 | 24 | 详细查看:https://www.cnblogs.com/index-html/p/http-cache-hotfix.html 25 | 26 | 27 | ## 检测浏览器代理 28 | 29 | 由于大部分 socks5 代理只转发数据,不转发 TCP 头,因此后端返回数据时附带一个特殊的 TCP 头,然后前端验证该头是否生效,即可推断否是存在代理。 30 | 31 | 例如后端下发 tcpwin=0 的控制信息,正常情况下前端收到后不会再往外发包,数据累计在协议栈缓冲区里。该特征可通过 WebSocket.bufferAmount 属性检测;而有代理的情况下,数据被累积在了代理服务的缓冲区,前端仍能往代理服务发包,缓冲区不会有累积。 32 | 33 | 演示:https://www.etherdream.com/proxy-detect/tcpwin.html 34 | 35 | 后端实现也很简单,NodeJS 实现 ws 服务,通过 setsockopt 给 socket 设置 mark,结合 tc 改包。 36 | 37 |
38 | SHOW ME THE CODE 39 | 40 | ```js 41 | // test.js 42 | const {setsockopt} = require('sockopt') 43 | const {WebSocketServer} = require('ws') 44 | const wss = new WebSocketServer({port: 8080}) 45 | 46 | wss.on('connection', (ws, req) => { 47 | console.log(req.socket.remoteAddress + ':' + req.socket.remotePort) 48 | setsockopt(req.socket, 1 /* SOL_SOCKET */, 36 /* SO_MARK */, 1 /* mark */) 49 | ws.send('') 50 | setTimeout(() => ws.terminate(), 2000) 51 | }) 52 | ``` 53 | 54 | ```bash 55 | # reset tc rules 56 | tc qdisc del dev eth0 root 57 | tc qdisc replace dev eth0 root handle 1: htb 58 | 59 | # if mark = 1 then tcp.win = 0 60 | tc filter add dev eth0 parent 1: u32 \ 61 | match mark 1 0xffffffff \ 62 | action pedit munge offset 34 u16 set 0 pipe \ 63 | csum ip and tcp 64 | 65 | npm install ws sockopt 66 | node test.js 67 | ``` 68 | 69 | HTTPS 同样支持。但不能运行在 CloudFlare 之类的服务后面,否则 TCP 特殊头就丢失了。如果网络会自动重算 checksum,那么 `pipe csum ip and tcp` 可省略。 70 |
71 | 72 | 73 | ## 发送 UDP 无状态包 74 | 75 | WebRTC 可发送 UDP 数据,但必须先经过握手等环节。有没有办法,第一个包就能携带自定义数据? 76 | 77 | WebRTC 传统用法是 P2P 通信,双方先通过 STUN 服务查询自己的公网地址并完成打洞,然后交换 SDP 等信息,相互连接。 78 | 79 | 但如果是 C/S 通信,服务端地址已知,那么客户端可跳过打洞步骤,直接虚构一份 SDP,把对方地址填进去就可以发包了。SDP 中的 `ice-ufrag` 会明文出现在 UDP 包中。该参数接受字母、数字和 #+-/=_ 共 68 种字符,最大长度 256,因此可携带一定量的信息到服务端。 80 | 81 | ---- 82 | 83 | 一个比较有意义的应用场景是端口敲门:目标服务器(任意服务都可以)默认禁止所有 IP,通过传送门页面给它发 UDP 敲门包。服务器收到预期的 UDP 后,将该包的源 IP 加入白名单。 84 | 85 | 演示:https://www.etherdream.com/port-knocking/ 86 | 87 | 点击按钮之前无法访问目标服务,点击按钮之后就可以访问了。使用这个方案,即可抵挡后台管理服务的暴力破解,以及其他的扫描流量。也可以用于 DDOS/CC 防御(比如用 GitHub Pages 这种打不垮的页面做传送门) 88 | 89 | ![image](https://user-images.githubusercontent.com/1072787/130002091-ff85caad-7866-423c-b41e-a84861553e52.png) 90 | 91 | ![image](https://user-images.githubusercontent.com/1072787/130002182-f14dfb40-400d-4e1f-ac4d-13d10a1c1432.png) 92 | 93 | 更多参考:https://www.cnblogs.com/index-html/p/js-port-knocking.html 94 | 95 | 96 | ## 获取往返数据包的 TTL 97 | 98 | 后端获取用户的 TTL 很容易,但在浏览器上获取后端的 TTL 很麻烦。 99 | 100 | 不过有个黑科技,可以让后端返回的包反弹回服务器 —— 只要前端在收到数据前释放 socket,之后操作系统找不到目标端口,就会发送「ICMP 端口不可到达」给服务器,其中封装了返回包的头部信息。 101 | 102 | 演示:https://www.etherdream.com/test/stunex.html 103 | 104 | 详细参考:https://www.cnblogs.com/index-html/p/js-get-round-trip-ttl.html 105 | 106 | 107 | # 更早的 108 | 109 | 下面大多从 weibo 搬运过来,账号 @EtherDream 去年被禁言,以后在此更新。表情符已替换成 ~(大部分可脑补成狗头) 110 | 111 | [2018.md](https://github.com/EtherDream/web-frontend-magic/blob/master/2018.md) 112 | 113 | [2017.md](https://github.com/EtherDream/web-frontend-magic/blob/master/2017.md) 114 | 115 | [2016.md](https://github.com/EtherDream/web-frontend-magic/blob/master/2016.md) 116 | 117 | [2015.md](https://github.com/EtherDream/web-frontend-magic/blob/master/2015.md) 118 | 119 | [2014.md](https://github.com/EtherDream/web-frontend-magic/blob/master/2014.md) -------------------------------------------------------------------------------- /2017.md: -------------------------------------------------------------------------------- 1 | 2 | # 2017-12-29 3 | 4 | 元旦期间,相信大家都被微信小游戏刷屏了,各种玩法攻略铺天盖地。当得知这是用 JS 开发时,立马想把过去写的 JS 游戏都翻新一遍。于是打开小游戏的官网,查看开发文档。 5 | 6 | 然而遗憾的是,小游戏虽然是用 JS 写的,但它并非运行在浏览器环境里,因此和 HTML 并不兼容。此外,在官网文档上,还看见一条奇葩的规则: 7 | 8 | ``` 9 | 2.与小程序一样,小游戏每次发布需要经过审核。我们在小程序和小游戏中都移除了动态执行代码的能力,包括以下调用方式: 10 | (1)eval 函数 11 | (2)setTimeout、setInterval 函数第一个参数传入代码字符串执行 12 | (3)使用 Function 传入字符串构造函数 13 | (4)使用 GeneratorFunction 传入字符串构造生成器函数 14 | ``` 15 | 16 | 咋一看貌似有些道理,要是开放 eval 的话,代码可以从网络上更新,就能绕过官方审核了。 17 | 18 | 但是,开发者若真想动态执行,那根本就是拦不住的 —— 在代码里藏一个虚拟机不就可以了吗。之前我们探讨[《使用虚拟机混淆 JavaScript 代码》](https://www.cnblogs.com/index-html/p/use_vm_protect_js.html)时,就讲解了 JS 虚拟机的概念,让程序根据不同的数据,执行不同的操作。虽然性能不高,但用于简单临时的场合,还是没问题的。 19 | 20 | 这时冒出个想法:要是能把性能优化得足够好的话,是不是可以让整个小游戏都由虚拟指令实现,这样程序只需发布一次就再也不用审核了呢? 21 | 22 | 于是开始探索,一个不用 eval、而是由 JS 自我驱动的图灵机,性能最高能达到多少。 23 | 24 | > 某些简单的场合性能可达 100%!细节分享: https://github.com/EtherDream/web-frontend-magic/issues/3 25 | 26 | 27 | 28 | # 2017-3-13 29 | 30 | 周末研究 WebGL2 时写了个 SHA256 PoW 的挖矿原型~ 31 | 32 | ![image](https://user-images.githubusercontent.com/1072787/68986888-08c0f480-085f-11ea-9040-6cdc55231b65.png) 33 | 34 | Demo: https://www.etherdream.com/FunnyScript/glminer/glminer.html 35 | 36 | 用笔记本自带的核显每秒可以 3000 万次左右的 SHA256 计算(2013 款 MBP)。如果有独显就更快了,试了下 Titan X 能跑出每秒 4.6 亿 hash/s 37 | 38 | 当然,即便能 100% 利用 GPU 也远没法和矿机比,更何况 WebGL 只有 50% 左右的效率。不过用于 XSS 分布式密码破解倒是不错,改天写一个破解 WPA2 的算法~ 39 | 40 | 41 | 42 | # 2017-3-8 43 | 44 | WebGL 2.0 API Quick Reference Guide 45 | 46 | ![image](https://user-images.githubusercontent.com/1072787/68986925-52a9da80-085f-11ea-8a32-5ea6ad6fab79.png) 47 | 48 | https://www.khronos.org/files/webgl20-reference-guide.pdf 49 | 50 | WebGL2 终于支持整数和位运算了! 51 | 52 | 曾有人试图用 [WebGL1 挖矿](https://github.com/derjanb/hamiyoca),由于不支持整数和位运算,只能靠浮点计算模拟,效率大大的低~ 53 | 54 | 55 | 56 | # 2017-3-6 57 | 58 | 5.4M 的 JS 文件。。。打开控制台就卡了十几秒,点 format 卡了半分钟~ 不过运行倒是很流畅 59 | 60 | ![image](https://user-images.githubusercontent.com/1072787/68987032-77eb1880-0860-11ea-9be6-e407cecfa7b5.png) 61 | 62 | ![image](https://user-images.githubusercontent.com/1072787/68987028-6e61b080-0860-11ea-82c6-0c53a2252f9f.png) 63 | 64 | 期待 WebAssembly 快点普及吧~ 65 | 66 | 67 | 68 | # 2017-3-5 69 | 70 | 写了个「阻止 XSS 自动发表留言」的案例,可以减缓蠕虫传播。试试你能不能绕过它~ 71 | 72 | Demo: https://www.etherdream.com/FunnyScript/anti-xssworm/ 73 | 74 | 原理很简单,用一个「跨源」的 iframe 充当按钮,起到 JS 隔离效果。另外,数据也通过 iframe 提交,后端通过 referer 即可判断是不是 iframe 提交的。 75 | 76 | 当然,这个方案阻止不了 clickjacking。 77 | 78 | > 详解:https://www.cnblogs.com/index-html/p/anti_xss_worm.html 79 | 80 | 81 | 82 | # 2017-3-2 83 | 84 | 经常看到有人讨论如果不能用 HTTPS 只能用 HTTP 页面,该如何对抗中间人劫持的问题。 85 | 86 | 其实可以用个黑科技缓解:浏览器强缓存。比如用 HTML5 AppCache、max-age 等将页面强缓存,子资源则通过 JS 加密传输。 87 | 88 | 这样可把风险降到首次访问上,以后就算遇到不安全的网络,访问入口页面仍是缓存里的内容(除非第一次访问时就被劫持,否则仍是之前遗留的安全内容)。 89 | 90 | 这种方案类似 TOFU(Trust on First Use,信任首次使用)的思想。 91 | 92 | 93 | 94 | # 2017-3-1 95 | 96 | 都忘了 `
` 标签还有个 `disabled` 属性,设置了可以把里面的表单控件都禁用。。。 97 | 98 | ![image](https://user-images.githubusercontent.com/1072787/68987116-6eae7b80-0861-11ea-96c0-d37b8a1ba4cb.png) 99 | 100 | Demo: https://jsfiddle.net/c4r9956m/ 101 | 102 |
103 | SHOW ME THE CODE 104 | 105 | ```html 106 |
107 | title 108 | 109 | A 110 | B 111 | 115 | 116 |
117 | ``` 118 |
119 | 120 | 121 | # 2017-2-28 122 | 123 | 在想 ServiceWorker 能不能和 WebRTC 配合使用,让静态资源都用 P2P 传输,节省服务器流量。。。 124 | 125 | > 已有人尝试过了,项目叫 PeerCDN,效果貌似并不好。 126 | 127 | 128 | 129 | # 2017-2-12 130 | 131 | 做了个保护网站弱口令的原型 132 | 133 | Demo: https://www.etherdream.com/webscrypt/example/login/ 134 | 135 | 大家可以尝试破解看。密码很短,并且是纯数字,破解成功会显示红包~ 136 | 137 | 算法和数据库都是公开的:https://github.com/EtherDream/WebScrypt/tree/master/example/login 138 | 139 | > 6 位数口令的还没有人破解,不过红包已经过期了。。。 140 | 141 | 142 | 143 | # 2017-2-11 144 | 145 | 周末更新了浏览器版的 scrypt 算法:https://github.com/EtherDream/WebScrypt 146 | 147 | ![image](https://user-images.githubusercontent.com/1072787/68987216-aec22e00-0862-11ea-9c4e-2a46f7002c41.png) 148 | 149 | 本来打算叫 scrypt.js 的,不过想了下也不全是 js 实现的,比如老版本浏览器用的就是 Flash,以后还会用到 WebAssembly。于是就叫 WebScrypt 了~ 150 | 151 | 现阶段主要亮点就是 asm.js 实现,并且在 C 代码上做了些修改,比如把 blockmix、salsa20 这些高频率执行的代码全部展开,放在同个栈上,这样就能避免大量的 TypedArray 访问。Chrome 下可提升 1 倍以上的性能,有兴趣的可[参考此处](https://github.com/EtherDream/WebScrypt/blob/master/src/c/smix.c#L46)。 152 | 153 | 另一个亮点是写了个小工具把 emscripten 生成的代码大幅精简,只保留基本的 asm.js 逻辑代码。原本生成的 js 有上万行,但大部分功能都用不到。当然这个小工具可能不是很通用,需要根据自己的需要改造。 154 | 155 | 还有就是通过 Flash 兼顾老版本浏览器的性能,所以从就算是 IE6 算力也不会太低(能有 asm.js 的一半左右),比自身的 JS 引擎快多了。 156 | 157 | 最后,关于这个项目的初衷,就是想在不增加后端硬件投入的前提下,通过纯前端实现,来增强网站的安全性,大幅降低暴力破解口令的难度(几千到几百万倍),这里有个[简单的演示](http://www.etherdream.com/webscrypt/example/login/),就算是弱口令也很难破解。 158 | 159 | (更多细节原理之后再讲解) 160 | 161 | > 这个项目很久没更新,有些地方需要大改动了~ 162 | 163 | 164 | 165 | # 2016 166 | 167 | [2016.md](https://github.com/EtherDream/web-frontend-magic/blob/master/2016.md) 168 | -------------------------------------------------------------------------------- /2016.md: -------------------------------------------------------------------------------- 1 | 2 | # 2016-9-7 3 | 4 | 2015 Password Hashing Competition 胜出者 —— `argon2` 终于有人移植成网页版了: 5 | 6 | https://github.com/P-H-C/phc-winner-argon2 7 | 8 | 不过该算法重度依赖 64 位整数计算,而 js/asm.js 并不原生支持 int64,只能用两个 32 位整数模拟,所以性能很低。还是期待 WebAssembly~ 9 | 10 | 为什么要在浏览器端 Hash 口令?这对安全有很大的提升,网站拖库后攻击者破解 Hash 的难度将会增加上百万倍!具体可参考之前写的:https://www.cnblogs.com/index-html/p/frontend-slow-hash.html 11 | 12 | 13 | 14 | # 2016-8-31 15 | 16 | 看见好多人在用 CSP 日志来跟踪运营商广告,其实 CSP 原本是用来拦截 XSS 的,上报外部资源只是个辅助功能,各种不好用。。。 17 | 18 | 其实现在的主流浏览器有一个接口:`performance.getEntries()`,可以取出网页加载过的所有资源: 19 | 20 | ![image](https://user-images.githubusercontent.com/1072787/68990089-e8f2f600-0889-11ea-8817-972e1b743d57.png) 21 | 22 | 几行代码就可以检测有没有加载异常的资源,比 CSP 灵活多了。 23 | 24 | ---- 25 | 26 | 另外还有一种跟踪资源加载的方案: 27 | 28 | ```js 29 | document.addEventListener('load', e => { 30 | console.log(e.target.src) 31 | }, true) 32 | ``` 33 | 34 | 虽然覆盖面没有前面那个大,但实时性强,并且兼容性更好,除了老 IE 外都能运行。熟悉前端的猜猜是什么原理~ 35 | 36 | 37 | 38 | # 2016-7-25 39 | 40 | Chrome49 支持 ``,W3C 总算是重视「跳转 opener」这种古老的钓鱼方式了。。。 41 | 42 | 43 | 44 | # 2016-7-22 45 | 46 | WebP 刚出来时感觉特别兴奋,还写了个 flash 版的解码器(用 alchemy 编译) 47 | 48 | https://www.etherdream.com/WebP/ 49 | 50 | 后来觉得并没什么卵用,而且解码很慢。不知道现在用 asm.js + worker 会不会快一些~ 51 | 52 | 53 | # 2016-7-14 54 | 55 | ```js 56 | Number.MAX_VALUE.toString(2) 57 | ``` 58 | 59 | 1024 bit,53 个 `1` 和 971 个 `0`。 60 | 61 | ```js 62 | "1111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 63 | ``` 64 | 65 | 66 | # 2016-7-9 67 | 68 | (非原创)前些时候看到一个 js 版的 “文曲星模拟器”: 69 | 70 | https://github.com/hackwaly/jswqx 71 | 72 | 镜像有几十 MB,如果直接 1:1 把 6502 指令翻译成 JS 的话估计超级大,性能可能比模拟还低。 73 | 74 | 75 | 76 | # 2016-7-8 77 | 78 | 上世纪 80 年代的 6502 CPU 指令“翻译”成 JavaScript~ 79 | 80 | ![image](https://user-images.githubusercontent.com/1072787/68990644-9a952580-0890-11ea-8c3a-d51ca3e3b77f.png) 81 | 82 | ![image](https://user-images.githubusercontent.com/1072787/68990647-9e28ac80-0890-11ea-8b7e-2ceedf8242b4.png) 83 | 84 | 贪吃蛇 Demo(ASWD 控制): http://www.etherdream.com/FunnyScript/6502snake/main.html 85 | 86 | 87 | 88 | # 2016-7-5 89 | 90 | 上回看到一个在线的 MOS 6502 CPU 的视觉图,于是突发奇想,能不能将 6502 指令 1:1 翻译成 JavaScrpt 呢?这样能直接在浏览器里运行,而不用模拟器。 91 | 92 | 于是遐想了几天,写了一些可行性的分析: 93 | 94 | https://www.cnblogs.com/index-html/p/translate-machine-code-to-javascript.html 95 | 96 | 后来发现实现也不困难,借助现有的工具即可。。。就当开开脑洞~ 97 | 98 | 99 | 100 | # 2016-6-10 101 | 102 | (非原创)一个在线模拟 6502 CPU 的网站: 103 | 104 | ![image](https://user-images.githubusercontent.com/1072787/68990744-d381ca00-0891-11ea-9eb6-b600d7c383a5.png) 105 | 106 | http://www.visual6502.org/JSSim/ 107 | 108 | 109 | 110 | # 2016-6-10 111 | 112 | (非原创)一个 asm.js 实现的红白机模拟机,性能不错,还有声音~ 113 | 114 | ![image](https://user-images.githubusercontent.com/1072787/68990764-0d52d080-0892-11ea-9865-a659773118ba.png) 115 | 116 | ![image](https://user-images.githubusercontent.com/1072787/68990769-104dc100-0892-11ea-8527-99ac5096a182.png) 117 | 118 | 演示:https://tsone.kapsi.fi/em-fceux/ 119 | 120 | 源码:https://bitbucket.org/tsone/em-fceux/ 121 | 122 | 内置了几个有趣的卡带,还从没见过开场画面的年份有 2000 之后的 NES 游戏~~~ 123 | 124 | 125 | # 2016-6-2 126 | 127 | Chrome 特有的压缩算法 brotli,1G 空文件可以压缩到 13KB。压缩率远超 GZip,和 LZMA 差不多了~ 128 | 129 | ![image](https://user-images.githubusercontent.com/1072787/68990780-2b203580-0892-11ea-91b2-369ffab1183c.png) 130 | 131 | ![image](https://user-images.githubusercontent.com/1072787/68990781-2d828f80-0892-11ea-97b8-a5eb0cb2fc5d.png) 132 | 133 | 感觉可以用来做压缩炸弹,比如把一个 1G 的 SVG 图片压缩到 10KB,然后通过外链作为论坛的签名~~~ 134 | 135 | 136 | # 2016-5-28 137 | 138 | (非原创)JS 版的 Python 解释器~ 139 | 140 | ![image](https://user-images.githubusercontent.com/1072787/68990832-be596b00-0892-11ea-8d29-434b41cbd66d.png) 141 | 142 | Demo: https://pypyjs.org/ 143 | 144 | 145 | # 2016-5-28 146 | 147 | (非原创)DOSBOX 的 asm.js 移植版,非常流畅,还有声音~ 148 | 149 | ![image](https://user-images.githubusercontent.com/1072787/68990843-e517a180-0892-11ea-9d77-a8ccfa3ef3a8.png) 150 | 151 | ![image](https://user-images.githubusercontent.com/1072787/68990840-dcbf6680-0892-11ea-8c0a-feab293bc8ec.png) 152 | 153 | 154 | GitHub: https://github.com/dreamlayers/em-dosbox 155 | 156 | Demo: https://classicreload.com/ 157 | 158 | 159 | 160 | # 2016-5-24 161 | 162 | 用 js 写算法就应该利用好语言特性。 163 | 164 | 比如数组越界不会抛出异常,位运算时会当做 0,可以节省一些判断;比如object 天生支持 string 为 key 的哈希表,而且性能很高。。。 165 | 166 | 类似的特性还有很多,不利用就浪费了。 167 | 168 | 169 | 170 | # 2016-5-19 171 | 172 | Chrome 目前要求 WebCrypto API 只能在 HTTPS 页面里使用。 173 | 174 | 个人感觉没有必要,即使没有这个 API 也可以用 JS 实现,只是性能低而已。 175 | 176 | 177 | 178 | # 2016-5-7 179 | 180 | 以前画的一个图,哪些环节会泄露你的密码。。。 181 | 182 | ![image](https://user-images.githubusercontent.com/1072787/68990938-1b095580-0894-11ea-9be3-6cab7ff3251d.png) 183 | 184 | 185 | 186 | # 2016-3-31 187 | 188 | 记得很久以前就有 VRML,现在 VR 出来了是不是该出 VRML5 了~ 189 | 190 | 191 | 192 | # 2016-3-22 193 | 194 | Mozilla 的又一个黑科技 `LLJS`:http://lljs.org/ 195 | 196 | ![image](https://user-images.githubusercontent.com/1072787/68990972-8f43f900-0894-11ea-8e9d-bf48120ea371.png) 197 | 198 | ![image](https://user-images.githubusercontent.com/1072787/68990974-91a65300-0894-11ea-9038-043b11c81608.png) 199 | 200 | 有点类似 asm.js,可以转换出高性能的 JS 代码。LLJS 语言有点像 C,可惜并不兼容,还得有学习成本,估计流行不了。 201 | 202 | > 貌似项目已经挂了。。。 203 | 204 | 205 | # 2016-3-21 206 | 207 | 神秘代码(番号)提取~~~ 208 | 209 | ```js 210 | document.body.textContent.match(/[A-Z]{2,}-\d{3,}/g) 211 | ``` 212 | 213 | 214 | # 2016-3-21 215 | 216 | TypeScript 里的 `const enum` 真心不错,直接编译成常量。 217 | 218 | ![image](https://user-images.githubusercontent.com/1072787/68991042-3032b400-0895-11ea-9ccb-1c0aee3df961.png) 219 | 220 | ![image](https://user-images.githubusercontent.com/1072787/68991043-34f76800-0895-11ea-8ba1-d63e57780881.png) 221 | 222 | 过去貌似只有 google closure compiler 里才能实现这种效果。 223 | 224 | 225 | 226 | # 2016-3-16 227 | 228 | 如果出一个 UglifyTS,压缩效果应该会更好吧,毕竟 TypeScript 能提供更多语言层的信息~ 229 | 230 | 231 | 232 | # 2016-2-26 233 | 234 | 恶作剧:真·乔布斯~ 235 | 236 | ```bash 237 | alias jobs="curl -L t.cn/RGp2Cg1" 238 | ``` 239 | 240 | ![image](https://user-images.githubusercontent.com/1072787/68991075-7f78e480-0895-11ea-804a-298cbf202013.png) 241 | 242 | 243 | 244 | # 2016-2-26 245 | 246 | `window[n]` 可得到页面第 n 个框架的 `contentWindow` (并且不受同源策略限制) 247 | 248 | `window.length` 可得到框架的个数。 249 | 250 | > 虽然是个冷知识,但在 XSS 中会用到。以后再详细介绍。 251 | 252 | 253 | 254 | # 2016-2-22 255 | 256 | 可提高 zip 压缩率的工具 `zopfli`,Google 出品。 257 | 258 | https://github.com/google/zopfli 259 | 260 | 配合 nginx 的 `gzip_static` 指令,资源先离线压缩,然后发布压缩包到服务器。这样即可节省存储、带宽资源,又避免了运行时压缩,大幅节省 CPU 资源。 261 | 262 | 另外该项目下还有个叫 `zopfli-png` 工具用于压缩 PNG 图片,压缩率比 pngout 还高。 263 | 264 | > br 压缩出现后,这种方案意义就不大了。除了老浏览器,以及非 HTTPS 页面(HTTP 页面不支持 br 压缩) 265 | 266 | 267 | 268 | # 2016-2-20 269 | 270 | 如何发送日志而不在控制台 Network 里显示? 271 | 272 |
273 | 点击查看答案 274 | 275 | 扔给 opener 上报(必须存在而且同源) 276 | 277 | 当然还有其他方案,大家可以想想,甚至都不用 HTTP/TCP 协议~ 278 |
279 | 280 | 281 | 282 | # 2015 283 | 284 | [2015.md](https://github.com/EtherDream/web-frontend-magic/blob/master/2015.md) 285 | 286 | -------------------------------------------------------------------------------- /2015.md: -------------------------------------------------------------------------------- 1 | # 2015-10-8 2 | 3 | 想到一个猥琐的方法,对付简单的运营商广告脚本,让它插入到错误的地方~ 4 | 5 | ```html 6 | 7 | 13 | 14 | 15 | 16 | Hello World 17 | 18 | 19 | ``` 20 | 21 | > 当然,这种方案只适用于插一次的情况,例如 nginx 设置了 `sub_filter_once on`。如果给所有的 `` 都插入那就没办法了。 22 | 23 | 24 | 25 | # 2015-9-8 26 | 27 | 看之前的 PPT 时翻到一个有趣的 Demo 28 | 29 | 30 | 31 | 32 | 33 | https://www.etherdream.com/webdraw/demo/bin/ 34 | 35 | 刚研究 HaXe 时突发奇想,用一种语言,同时生成 HTML5 和 Flash 两个版本。这样就不用考虑低版本浏览器的兼容性问题了。 36 | 37 | > 关于使用 haXe 做小游戏的优势,在[这个 PPT](https://github.com/EtherDream/myppt/blob/master/JS%E5%B0%8F%E6%B8%B8%E6%88%8F%E5%88%B6%E4%BD%9C%E6%8A%80%E5%B7%A7.pdf)中有讲解。 38 | 39 | 40 | # 2015-8-28 41 | 42 | Cloud9 试用版都那么强大! 43 | 44 | ![image](https://user-images.githubusercontent.com/1072787/69002872-68d49b00-0932-11ea-9629-2fa0daf818c8.png) 45 | 46 | ![image](https://user-images.githubusercontent.com/1072787/69002921-c7e6df80-0933-11ea-954e-1522b4e67e58.png) 47 | 48 | 49 | 50 | # 2015-8-20 51 | 52 | 有趣的 emoji 效果: 53 | 54 | ```js 55 | var i = 0 56 | var arr = ['🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘'] 57 | setInterval(function() { 58 | location.hash = arr[i++ % arr.length] 59 | }, 50); 60 | ``` 61 | 62 | 如果地址栏里不想有 `#`,可换成: 63 | 64 | ```js 65 | setInterval(function() { 66 | history.replaceState('', '', '/' + arr[i++ % arr.length]) 67 | }, 50); 68 | ``` 69 | 70 | 71 | # 2015-8-13 72 | 73 | 无意中发现 nginx 有个 `gunzip` 的指令,终于解决了无法在 gzip 网页中使用 `sub_filter` 的问题。 74 | 75 | 之前研究中间人攻击时,为了能在 HTML 中插入脚本,代理过程中还得让把请求头 `Accept-Encoding` 去掉,让服务器不返回压缩格式,才能顺利执行 `sub_filter`。但这样又会浪费网络流量,很是纠结。 76 | 77 | 现在有了 `gunzip`,只需在 nginx 内部再套一次代理,即可注入 JS 到压缩后的页面里了~ 78 | 79 | ```nginx 80 | # nginx.conf 81 | events { 82 | worker_connections 1024; 83 | } 84 | 85 | http { 86 | resolver 8.8.8.8; 87 | server { 88 | listen 8080; 89 | gzip on; 90 | 91 | location / { 92 | proxy_set_header host $http_host; 93 | proxy_pass http://unix:/tmp/mitm.sock; 94 | 95 | sub_filter console.warn("inject!!!") 165 | 点击查看答案 166 | 167 | ```js 168 | // 目标:获取闭包内容的 token 变量,提交给 check 校验 169 | // 备注: 170 | // 执行环境需联网,总用时不超过 10s 171 | // 兼容现代浏览器即可,自己弹 alert('win') 不算~ 172 | (function() { 173 | var token = '$' + Math.random() 174 | 175 | new Image().src = 'https://www.baidu.com/s?wd=' + token 176 | 177 | window.check = function(v) { 178 | if (v === token) { 179 | alert('win') // 通过 180 | } 181 | } 182 | })() 183 | 184 | 185 | // 你的代码写在此处... 186 | setTimeout(function() { 187 | performance.getEntries().forEach(function(item) { 188 | var r = item.name.split('$0.') 189 | if (r.length > 1) { 190 | var key = '$0.' + r[1] 191 | check(key) 192 | } 193 | }) 194 | }, 3000) 195 | ``` 196 | 197 | 198 | 199 | 200 | # 2015-8-25 201 | 202 | Chrome 终于支持 DOM 原型上的 getter / setter。过去写的[《前端防火墙 -- 可疑模块拦截》](https://fex.baidu.com/blog/2014/06/xss-frontend-firewall-2/) 可以大幅精简了。 203 | 204 | ![image](https://user-images.githubusercontent.com/1072787/69005230-efe93980-0959-11ea-8fac-9f769495e612.png) 205 | 206 | 207 | 208 | 209 | # 2015-7-29 210 | 211 | 之前写[《XSS 前端防火墙 —— 内联事件拦截》](https://fex.baidu.com/blog/2014/06/xss-frontend-firewall-1/ 212 | )时,漏一个原理图,现补上: 213 | 214 | 215 | 216 | 217 | 218 | # 2015-7-27 219 | 220 | [HTML5 Service Workers](https://www.w3.org/TR/2015/WD-service-workers-20150625/) 可以接管浏览器网络请求,本以为 MITM 攻击又有新玩法了,结果这货只能在 HTTPS 下开启。。。 221 | 222 | 查了下原来人家早就考虑到了~ 223 | 224 | ![image](https://user-images.githubusercontent.com/1072787/69005259-80c01500-095a-11ea-9fc1-5f8e46daf1d6.png) 225 | 226 | 227 | 228 | # 2015-6-4 229 | 230 | FireFox 居然会检测「扩展名」和「MIME」是否匹配,就这点比其他浏览器有进步~ 231 | 232 | 而 Chrome 仍然可以玩扩展名的小把戏,例如扩展名是 GIF 的 URL 也可以运行 JS: 233 | 234 | https://www.etherdream.com/upload/20150603.gif 235 | 236 | 237 | 238 | # 2015-5-8 239 | 240 | 设置了 `X-Frame-Options` 的页面怎么玩反射型 XSS? 241 | 242 | 如果当前存在来源页的话,跳转 `opener.location` 就可以(并且这个属性无视同源策略~) 243 | 244 | 245 | 246 | # 2015-5-7 247 | 248 | TypeScript 编译器居然是用 TypeScript 实现的,最终编译成 JS 跑在 NodeJS 里。。。 249 | 250 | 虽说语言自举一直都是惯例,但毕竟 JS 效率很低,导致 TS 编译很慢,半天电脑就滚烫了~ 251 | 252 | 253 | 254 | # 2015-5-6 255 | 256 | 恶作剧 XSS: 257 | 258 | ```js 259 | for (i = 0; i < 4; i++) { 260 | document.cookie = i + '=' + 'X'.repeat(3000) 261 | } 262 | ``` 263 | 264 | ![image](https://user-images.githubusercontent.com/1072787/69005395-acdc9580-095c-11ea-82f6-b610e8120b08.png) 265 | 266 | > 详解:https://www.cnblogs.com/index-html/p/cookie-dos.html 267 | 268 | 269 | 270 | # 2015-4-20 271 | 272 | 想到一个测试用户是否上过某网站的方法:加载该网站 logo,瞬间完成说明有缓存,之前访问过;反之亦然~ 273 | 274 | 275 | 276 | # 2015-4-14 277 | 278 | 不禁用第三方 cookie 实在太危险了~ 一大波应用被坑死 279 | 280 | 281 | 282 | # 2015-3-31 283 | 284 | 非 80 端口的 IP 也能河蟹。。。 285 | 286 | 287 | 288 | ![image](https://user-images.githubusercontent.com/1072787/69005479-fa0d3700-095d-11ea-9903-ff4bc9de0164.png) 289 | 290 | 291 | 292 | # 2015-3-17 293 | 294 | 未来 webapp 头部会不会加上这句~~ 295 | 296 | ```html 297 | 300 | ``` 301 | 302 | 303 | # 2015-3-5 304 | 305 | 静态资源存 localStorage 就是水坑漏洞的前兆,风险远远大于优化。 306 | 307 | 308 | 309 | # 2015-3-2 310 | 311 | 可以用 CSP 监控 HTTPS 中的 HTTP 资源,只允许 `https://*` 即可找出全站 HTTPS 升级中的遗漏点~ 312 | 313 | 或者用之前提到的 onload/onerror 监控资源加载: 314 | 315 | https://www.cnblogs.com/index-html/p/use-onload-event-trace-http-hijack.html 316 | 317 | 相比 CSP,这种方案上报的信息更详细,方便排查。 318 | 319 | 320 | 321 | # 2015-3-1 322 | 323 | `bj.cn` 居然和 `com.cn` 一样,都是顶级域名~ 324 | 325 | 查了下 TLD 的官方列表:https://publicsuffix.org/list/effective_tld_names.dat 326 | 327 | 居然有这么多,而且还有这么长的顶级域名:`higashimatsuyama.saitama.jp` 328 | 329 | 330 | # 2015-2-3 331 | 332 | JS 页面截屏的效果~ 333 | 334 | ![image](https://user-images.githubusercontent.com/1072787/69006857-66913180-0970-11ea-9c5d-f7822d4ca985.png) 335 | 336 | ![image](https://user-images.githubusercontent.com/1072787/69006851-4bbebd00-0970-11ea-8827-63068ffba2e5.png) 337 | 338 | ![image](https://user-images.githubusercontent.com/1072787/69006853-5711e880-0970-11ea-981f-377f479d9660.png) 339 | 340 | 原理很简单,JS 采集整个 DOM 树,以及鼠标位置、滚动条坐标等等,编码压缩后发给后端。 341 | 342 | 后端根据这些信息,在相同的浏览器内核中渲染出用户当前看到的网页模样。 343 | 344 | 同时,根据 User-Agent 大致模仿浏览器的外观~ 345 | 346 | 不过目前只能静态截图,之后再改进成动态录屏的效果~ 虽然连续不断的截图也可以当做动画,但效率太低。目前在考虑使用一些 diff 算法,只需很小的开销就可以实现高 fps 录屏。 347 | 348 | 349 | 350 | # 2015-1-7 351 | 352 | 十年前的手绘黑魔法。。。如果还能找到,之后继续分享~ 353 | 354 | ![image](https://user-images.githubusercontent.com/1072787/69006950-026f6d00-0972-11ea-918b-fde25e27843f.png) 355 | 356 | ![image](https://user-images.githubusercontent.com/1072787/69006952-08fde480-0972-11ea-8b81-2a282e3fc385.png) 357 | 358 | ![image](https://user-images.githubusercontent.com/1072787/69006942-d8b64600-0971-11ea-95e0-87cb6b08e0e3.png) 359 | 360 | 361 | # 2014 362 | 363 | [2014.md](https://github.com/EtherDream/web-frontend-magic/blob/master/2014.md) 364 | -------------------------------------------------------------------------------- /2018.md: -------------------------------------------------------------------------------- 1 | # 2018-12-19 2 | 3 | 有人说,能用 const 的时候尽量用 const。所以,循环因子也可以。。。 4 | 5 | ```js 6 | for (const i of range(0, 5)) { 7 | console.log(i) // 0, 1, 2, 3, 4 8 | } 9 | 10 | function* range(beg, end, step = 1) { 11 | for (let i = beg; i < end; i += step) 12 | yield i 13 | } 14 | ``` 15 | 16 | > 有没有 Python 的感觉~ 17 | 18 | 19 | 20 | # 2018-11-19 21 | 22 | 思考题:如何获取闭包内 key 变量的值: 23 | 24 | ```js 25 | // 挑战目标:获取 key 的值 26 | (function() { 27 | // 一个内部变量,外部无法获取 28 | var key = Math.random() 29 | 30 | console.log('[test] key:', key) 31 | 32 | // 一个内部函数 33 | function internal(x) { 34 | return x 35 | } 36 | 37 | // 对外暴露的函数 38 | apiX = function(x) { 39 | try { 40 | return internal(x) 41 | } catch (err) { 42 | return key 43 | } 44 | } 45 | })() 46 | 47 | // 你的代码写在此处: 48 | // ... 49 | ``` 50 | 51 |
52 | 点击查看答案 53 | 54 | https://github.com/EtherDream/web-frontend-magic/issues/1 55 |
56 | 57 | 58 | # 2018-11-19 59 | 60 | 思考题:检测隐形人是否存在 61 | 62 | ```js 63 | // 挑战目标:检测 Math 是否被代理 64 | if (Math.random() < 0.5) { 65 | console.log('hooked') 66 | 67 | self.Math = new Proxy(Math, { 68 | get(obj, prop) { 69 | return obj[prop] 70 | } 71 | }) 72 | } 73 | 74 | // 你的代码写在此处: 75 | // 如果控制台有显示 hooked,那么你输出 true,反之 false 76 | // ... 77 | ``` 78 | 79 |
80 | 点击查看答案 81 | 82 | 答案有多个,但有一种特别巧妙,可以参考 [如何获取闭包内 key 变量的值](https://github.com/EtherDream/web-frontend-magic/issues/1) 的思路。 83 |
84 | 85 | 86 | 87 | # 2018-10-26 88 | 89 | 点一下,CPU 开始咆哮 90 | 91 | Demo: https://www.etherdream.com/FunnyScript/cpu-hog/ 92 | 93 | > 该页面创建 1000 个 Service Worker 消耗大量 CPU。即使关闭页面,它们仍在后台运行。想尝试的话务必在隐身模式中打开,感觉卡了就可以关闭了。 94 | 95 | 96 | 97 | # 2018-10-18 98 | 99 | 一种统计 key 的个数,无需使用判断的写法: 100 | 101 | ```js 102 | const map = {} 103 | const str = 'hello world' 104 | 105 | str.split('').forEach(key => { 106 | map[key] = -~map[key] 107 | }) 108 | 109 | console.log(map) 110 | // {" ": 1, d: 1, e: 1, h: 1, l: 3, o: 2, r: 1, w: 1} 111 | ``` 112 | 113 | Demo: https://jsbin.com/lumexovida/edit?js,console,output 114 | 115 | > ~i = -(i + 1),~undefined = -1 116 | 117 | 118 | 119 | # 2018-10-17 120 | 121 | 自从 Chrome 69 支持 OffscreenCanvas API 后,终于能在 Service Worker 里调用 GPU 资源了~ 所以用户关闭网页后,XSS 还可以继续使用 100% CPU 和 GPU 资源几分钟时间~ 122 | 123 | 拿之前的 SHA256 PoW 改了下貌似可行~ 124 | 125 | Demo: https://www.etherdream.com/FunnyScript/glminer/sw-miner/ 126 | 127 |
128 | 点击预览图片 129 | 130 | ![image](https://user-images.githubusercontent.com/1072787/68910425-aeeffa00-078c-11ea-96ed-3e50a39f97ed.png) 131 | 132 | ![image](https://user-images.githubusercontent.com/1072787/68910436-b44d4480-078c-11ea-8bf9-fd8637bd91f8.png) 133 | 134 | ![image](https://user-images.githubusercontent.com/1072787/68910445-b8796200-078c-11ea-90c8-5448dce37f35.png) 135 |
136 | 137 | 当然,用 GPU 挖矿意义不大,网页还是适合挖 CPU 算法的币。 138 | 139 | 不过 GPU 这种通用的硬件,显然更适合破解密码,比如 WiFi 密码。Shader 好好优化下,破解速度可以达到 hashcat 一半左右。论坛 XSS 每个用户贡献几分钟,还是不错的~ WiFi 破解后,还可以劫持流量植入 JS,于是又可以增加一些算力~ 140 | 141 | > 关于 Service Worker 各种玩法,可参考 https://github.com/etherdream/sw-sec 142 | 143 | 144 | 145 | # 2018-9-28 146 | 147 | 思考题:如何实现一个网页版的 CPU 跑分程序,并且带有用户排行榜功能。(重点是确保用户不易作弊,比如自定义提交成绩;以及不能使用多核 CPU 甚至 GPU 来加速,只拼单核性能) 148 | 149 | > 哪些密码学算法是无法利用多线程加速的,并且能在网页里高效率运行? 150 | 151 | 152 | 153 | # 2018-9-12 154 | 155 | Win1.0 的 calc.exe(非原创) 156 | 157 | ![image](https://user-images.githubusercontent.com/1072787/68911012-a1d40a80-078e-11ea-9128-2ff1a5363326.png) 158 | 159 | Demo: https://classicreload.com/Windows-1-01.html 160 | 161 | > Win1.0 只比 Win10 差一点而已~ 162 | 163 | 164 | 165 | # 2018-9-11 166 | 167 | 直到现在,仍有相当多的用户甚至开发者都不知道【允许三方 Cookie】存在多大的危险~ 168 | 169 | 一句话概况【允许三方 Cookie】的危险:在不安全的网络环境下,访问任何一个 HTTP 页面,各大网站 Cookie 可能瞬间被中间人拿到。 170 | 171 | ![image](https://user-images.githubusercontent.com/1072787/68911051-c03a0600-078e-11ea-96e3-01c89173af92.png) 172 | 173 | 174 | > 原理说过很多次了,不再解释 175 | 176 | 177 | 178 | # 2018-9-7 179 | 180 | 出个思考题:尝试读取 obj 中那个带随机数的隐藏属性 181 | 182 | ```js 183 | var obj = {} 184 | 185 | Object.defineProperty(obj, '$' + Math.random(), { 186 | get: () => alert('You win!'), 187 | enumerable: false, 188 | }) 189 | 190 | // write code here: 191 | ``` 192 | 193 |
194 | 点击查看答案 195 | 196 | ```js 197 | var obj = {}; 198 | 199 | Object.defineProperty(obj, '$' + Math.random(), { 200 | get: () => alert('You win!'), 201 | enumerable: false, 202 | }); 203 | 204 | // write code here: 205 | // 答案 1 206 | obj[Object.keys(Object.getOwnPropertyDescriptors(obj))[0]]; 207 | 208 | // 答案 2 209 | obj[Reflect.ownKeys(obj)[0]]; 210 | ``` 211 | 212 | 想想还有没有更多答案~ 213 | 214 |
215 | 216 | 217 | 218 | # 2018-8-17 219 | 220 | 有什么场合,必须使用 ES6 的 Reflect? 221 | 222 |
223 | 点击查看答案 224 | 225 | https://github.com/EtherDream/web-frontend-magic/issues/2 226 |
227 | 228 | 229 | # 2018-8-1 230 | 231 | 思考题:用最少的字符实现下图效果。 232 | 233 | (鼠标悬浮在超链接上,状态栏显示的是网站 A,但点击进入的却是网站 B) 234 | 235 | ![image](https://user-images.githubusercontent.com/1072787/68911068-c8924100-078e-11ea-9be1-4aa221ea20fb.png) 236 | 237 | ![image](https://user-images.githubusercontent.com/1072787/68911082-cfb94f00-078e-11ea-85b2-5d41b2ed2f92.png) 238 | 239 | 当然这个是上古时代的黑魔法了,稍懂前端的都知道怎么实现。所以这里只问最短的实现~ 240 | 241 | 目前想到的是 55 字符(包括目标域名):https://www.etherdream.com/FunnyScript/statusbar_spoof_2.html 242 | 243 |
244 | 点击查看答案 245 | 246 | ```html 247 | tmall 248 | ``` 249 |
250 | 251 | 252 | ---- 253 | 254 | 讲解:超链接和 `location` 很像,都有 `href`、`host` 等 URL 属性。不少人以为只有 `href` 属性可赋值,事实上其他属性也可以。 255 | 256 | 比如想把当前页面从 http 跳转到 https,只需修改 `protocol` 即可: 257 | 258 | ```js 259 | location.protocol = 'https:' 260 | ``` 261 | 262 | 另外 HTML 内联事件默认套有 `with(this)`,所以可省略 `this.` 这几个字符。 263 | 264 | 265 | 266 | # 2018-7-27 267 | 268 | 一种检测 HTTPS 中间人降级攻击的猥琐思路~ 269 | 270 | ```html 271 | 276 | ``` 277 | 278 | 在公司的脚本上尝试后发现竟然有不少日志,看来这类攻击目前还是存在的。。。 279 | 280 | > HTTPS 中间人降级攻击,本质上就是把流量中的 `https://` 替换成 `http://`。所以又称 -1s 攻击~ 281 | 282 | 283 | 284 | # 2018-7-26 285 | 286 | 由于大部分用户都不会开启浏览器 `Do Not Track`,因此少数开了的用户反而成了另类,被用于浏览器指纹特征了。。。 287 | 288 | 289 | 290 | # 2018-7-20 291 | 292 | 思考题:在 JS 中用 0 0 0 0 四个常量计算 24,只能用符号,表达式越短越好。例如: 293 | 294 | ```js 295 | -~-~-~0<<-~0-~0-~0 // 24 296 | ``` 297 | 298 | 目前已知最短 14 个字符~ 299 | 300 |
301 | 点击查看答案 302 | 303 | ```js 304 | !0-~!0< 307 | 308 | 309 | # 2018-6-6 310 | 311 | BitInt 出现后,不用死循环也能实现 CPU 100% 的效果了。一个 2 层幂塔就能卡死浏览器~ 312 | 313 | ```js 314 | 9n ** 9n ** 9n > 0 315 | ``` 316 | 317 | ---- 318 | 319 | 为什么这里要加 > 0 的判断,因为 320 | 321 | ``` 322 | 9 ^ 9 ^ 9 ≈ 4.28 x 10^369693099 323 | ``` 324 | 325 | 这个数字,光是位数就有 `369,693,099` 之多,相当于控制台要输出一个 300 多兆的字符串!所以为了不在输出时卡死,于是加了个判断。 326 | 327 | (事实上基本等不到字符串输出那步) 328 | 329 | 330 | 331 | # 2018-5-22 332 | 333 | nodejs 恶作剧:给系统创建一个叫 `node_modules` 的用户,然后 `npm install` 就无法使用了~~~ 334 | 335 |
336 | 点击预览图片 337 | 338 | ![image](https://user-images.githubusercontent.com/1072787/68911116-ea8bc380-078e-11ea-8860-666775ecd005.png) 339 | 340 | ![image](https://user-images.githubusercontent.com/1072787/68911122-ee1f4a80-078e-11ea-84c7-c5fc9374764d.png) 341 |
342 | 343 | > 如果真遇到项目文件夹之外有 `node_modules` 的话,只要在 `npm install` 时加上参数 `--prefix path` 就可以强制指定 `node_modules` 的路径。 344 | 345 | 346 | 347 | # 2018-5-21 348 | 349 | 之前遇到个网站 WAF 的 JS 脚本,代码经过多次动态混淆。 350 | 351 | 为了防止被人调试,前端不断执行 debugger 指令,然后检测执行用时 —— 如果控制台开着,debugger 指令会触发断点,用时显然高出平常。于是 JS 会给后端发送日志,然后 IP 就被网站 ban 了。 352 | 353 | ```js 354 | setInterval(function() { 355 | var t1 = Date.now(); 356 | debugger; 357 | var t2 = Date.now(); 358 | if (t2 - t1 > 100) { 359 | console.log('debug detected'); 360 | // send_log('ban this ip'); 361 | } 362 | }, 500); 363 | ``` 364 | 365 | 简单演示:https://codepen.io/anon/pen/rvPYxR?editors=0010 366 | 367 | 当然,在经过几次 IP 更换后,很快就摸索出了一个超级简单的规避方案。猜猜是如何实现~ 368 | 369 |
370 | 点击查看答案 371 | 372 | 其实非常简单,禁用调试器断点功能就可以,比如 Chrome DevTool 的箭头图标。 373 | 374 | 375 | 376 | 377 | 不过想要一次成功,还是需要些小技巧的,毕竟刚打开 DevTool 的时候还是会触发 debugger 断下来的: 378 | 379 | ![image](https://user-images.githubusercontent.com/1072787/68911167-0becaf80-078f-11ea-9346-b2ac0fc1d405.png) 380 | 381 | 所以正确的打开方式,应该先随便开一个网页,打开 DevTool 禁用断点: 382 | 383 | ![image](https://user-images.githubusercontent.com/1072787/68911171-0e4f0980-078f-11ea-83b3-2d4c137b1d7f.png) 384 | 385 | 然后再打开想要访问的网页,这时 debugger 就不会触发了: 386 | 387 | ![image](https://user-images.githubusercontent.com/1072787/68911176-10b16380-078f-11ea-9020-d3480172c6cd.png) 388 |
389 | 390 | 391 | # 2018-5-21 392 | 393 | 大写的 αß 服不服~ 394 | 395 | ```js 396 | 'αß'.toUpperCase() // "ΑSS" 397 | ``` 398 | 399 | 类似的还有 `'ffi'.toUpperCase() === 'FFI'`。然而 `'嬲'.toUpperCase() !== '男女男'` ~ 400 | 401 | 所以判断长度限制必须在转换之后,否则会有溢出风险。 402 | 403 | 404 | 405 | # 2018-5-21 406 | 407 | 随着 JS 引擎优化能力的提升,越来越多的性能黑魔法将会消失~ 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | # 2018-5-15 416 | 417 | 思考题:定义 x 使得满足条件判断,字数越少越好。 418 | 419 | ```js 420 | const x = _______ 421 | const win = ('a' in x) && !('a' in x) 422 | console.log(win) // true 423 | ``` 424 | 425 | 目前已知最短 28 个字符~ 426 | 427 |
428 | 点击查看答案 429 | 430 | ```js 431 | const x = new Proxy(T=_=>T^=1,{has:T}) 432 | const win = ('a' in x) && !('a' in x) 433 | alert(win) // true 434 | ``` 435 |
436 | 437 | 438 | 439 | # 2018-5-14 440 | 441 | 思考题:有些 JS 代码混淆后,会变成 `eval(一大坨代码)` 的形式。当然解密也非常容易,把 `eval` 换成 `console.log` 就能原形毕露。 442 | 443 | 下面请思考,如何在「一大坨代码」中加入陷阱,跟踪有哪些人把 `eval` 换成了其他的函数? 444 | 445 |
446 | 点击查看答案 447 | 448 | ```js 449 | eval( (function() { // 换成 console.log 试试 450 | 451 | // 解码程序 452 | var code = [ 453 | 'ZG9jdW1lbnQuYm9keS5pbm', 454 | '5lckhUTUwgPSAnc2NyaXB0', 455 | 'IHJ1bm5pbmcgLi4uJzs=' 456 | ]; 457 | 458 | code = atob(code.join('')); 459 | 460 | // 此外省略几百行... 461 | 462 | // 埋一个陷阱 463 | T = setTimeout(function() { 464 | alert('哈哈,你掉进陷阱里了!'); 465 | 466 | // 本地存储里隐写一个标记,长期跟踪 467 | // 释放 CSRF 漏洞,获取你的隐私~ 468 | // 或者,开启自毁程序 ... 469 | 470 | }, 0); 471 | 472 | // 此外省略几百行... 473 | 474 | // 解码程序 475 | code += 'clearTimeout(T)'; 476 | 477 | // 此外省略几百行... 478 | 479 | return code; 480 | })() ); 481 | ``` 482 |
483 | 484 | 485 | 486 | # 2018-5-14 487 | 488 | 如何使用 JS 缓解网站 DDOS 的攻击? 489 | 490 | https://yq.aliyun.com/articles/236585 491 | 492 | 大致原理:网页多用强缓存(目前是 Service Worker),发生故障时可毫秒级切换流量到 N 个后备节点。网站被打垮也只影响新用户,老用户照样可以流畅访问~ 493 | 494 | > 当然这其中细节问题很多,以后会在 https://github.com/EtherDream/js-anti-ddos 中讨论。 495 | 496 | 497 | 498 | # 2018-5-8 499 | 500 | 相册里翻到个上古时代用 `