
收集整理過去發表的 #前端黑魔法# 話題。
在此懷念和 @zswang 交流探讨前端黑魔法的時光
原文連結:
https://github.com/EtherDream/web-frontend-magic2019
整理中...
下面大多從 weibo 搬運過來,賬号 @EtherDream 去年被禁言,以後在此更新。表情符已替換成 ~(大部分可腦補成狗頭)
2018-12-19
有人說,能用 const 的時候盡量用 const。是以,循環因子也可以。。。
for (const i of range(0, 5)) {
console.log(i) // 0, 1, 2, 3, 4
}
function* range(beg, end, step = 1) {
for (let i = beg; i < end; i += step)
yield i
}
有沒有 Python 的感覺~
2018-11-19
思考題:如何擷取閉包内 key 變量的值:
// 挑戰目标:擷取 key 的值
(function() {
// 一個内部變量,外部無法擷取
var key = Math.random()
console.log('[test] key:', key)
// 一個内部函數
function internal(x) {
return x
}
// 對外暴露的函數
apiX = function(x) {
try {
return internal(x)
} catch (err) {
return key
}
}
})()
// 你的代碼寫在此處:
// ...
答案:
https://github.com/EtherDream/web-frontend-magic/issues/1思考題:檢測隐形人是否存在
// 挑戰目标:檢測 Math 是否被代理
if (Math.random() < 0.5) {
console.log('hooked')
self.Math = new Proxy(Math, {
get(obj, prop) {
return obj[prop]
}
})
}
// 你的代碼寫在此處:
// 如果控制台有顯示 hooked,那麼你輸出 true,反之 false
// ...
Demo:
https://jsfiddle.net/k0nupd58/答案有多個,但有一種特别巧妙,可以參考「如何擷取閉包内 key 變量的值」的思路。
2018-10-26
點一下,CPU 開始咆哮
https://www.etherdream.com/FunnyScript/cpu-hog/該頁面建立 1000 個 Service Worker 消耗大量 CPU。即使關閉頁面,它們仍在背景運作。想嘗試的話務必在隐身模式中打開,感覺卡了就可以關閉了。
2018-10-18
一種統計 key 的個數,無需使用判斷的寫法:
const map = {}
const str = 'hello world'
str.split('').forEach(key => {
map[key] = -~map[key]
})
console.log(map)
// {" ": 1, d: 1, e: 1, h: 1, l: 3, o: 2, r: 1, w: 1}```
Demo: [https://jsbin.com/lumexovida/edit?js,console,output](https://jsbin.com/lumexovida/edit?js,console,output)
> ~i = -(i + 1),~undefined = -1
**2018-10-17**
自從 Chrome 69 支援 OffscreenCanvas API 後,終于能在 Service Worker 裡調用 GPU 資源了~ 是以使用者關閉網頁後,XSS 還可以繼續使用 100% CPU 和 GPU 資源幾分鐘時間~
拿之前的 SHA256 PoW 改了下貌似可行~
Demo: [https://www.etherdream.com/FunnyScript/glminer/sw-miner/](https://www.etherdream.com/FunnyScript/glminer/sw-miner/)



當然,用 GPU 挖礦意義不大,網頁還是适合挖 CPU 算法的币。
不過 GPU 這種通用的硬體,顯然更适合破解密碼,比如 WiFi 密碼。Shader 好好優化下,破解速度可以達到 hashcat 一半左右。論壇 XSS 每個使用者貢獻幾分鐘,還是不錯的~ WiFi 破解後,還可以劫持流量植入 JS,于是又可以增加一些算力~
關于 Service Worker 各種玩法,可參考 [https://github.com/etherdream/sw-sec](https://github.com/etherdream/sw-sec)
**2018-9-28**
思考題:如何實作一個網頁版的 CPU 跑分程式,并且帶有使用者排行榜功能。(重點是確定使用者不易作弊,比如自定義送出成績;以及不能使用多核 CPU 甚至 GPU 來加速,隻拼單核性能)
> 哪些密碼學算法是無法利用多線程加速的,并且能在網頁裡高效率運作?
**2018-9-13**
《大航海時代 2》風格的 Google Map
Demo: [https://jsfiddle.net/84j1cvt9/29/](https://jsfiddle.net/84j1cvt9/29/)


**2018-9-12**
Win1.0 的 calc.exe(非原創)

Demo: [https://classicreload.com/Windows-1-01.html](https://classicreload.com/Windows-1-01.html)
> Win1.0 隻比 Win10 差一點而已~
**2018-9-11**
直到現在,仍有相當多的使用者甚至開發者都不知道【允許三方 Cookie】存在多大的危險~
一句話概況【允許三方 Cookie】的危險:在不安全的網絡環境下,通路任何一個 HTTP 頁面,各大網站 Cookie 可能瞬間被中間人拿到。

> 原理說過很多次了,不再解釋
**2018-9-7**
出個思考題:嘗試讀取 obj 中那個帶随機數的隐藏屬性
var obj = {}
Object.defineProperty(obj, '$' + Math.random(), {
get: () => alert('You win!'),
enumerable: false,
})
// write code here:
`
https://jsfiddle.net/2c358wxp/ 有多個答案
2018-8-17
有什麼場合,必須使用 ES6 的 Reflect?
https://github.com/EtherDream/web-frontend-magic/issues/22018-8-1
思考題:用最少的字元實作下圖效果。
(滑鼠懸浮在超連結上,狀态欄顯示的是網站 A,但點選進入的卻是網站 B)
當然這個是上古時代的黑魔法了,稍懂前端的都知道怎麼實作。是以這裡隻問最短的實作~
目前想到的是 55 字元(包括目标域名):
https://www.etherdream.com/FunnyScript/statusbar_spoof_2.html講解:超連結和 location 很像,都有 href、host 等 URL 屬性。不少人以為隻有 href 屬性可指派,事實上其他屬性也可以。
比如想把目前頁面從 http 跳轉到 https,隻需修改 protocol 即可:
location.protocol = 'https:'
另外 HTML 内聯事件預設套有 with(this),是以可省略 this. 這幾個字元。
2018-7-27
一種檢測 HTTPS 中間人降級攻擊的猥瑣思路~
<script>
if ('https://a.com'.startsWith('http:')) {
// send_log('SSLStrip detected')
}
</script>
在公司的腳本上嘗試後發現竟然有不少日志,看來這類攻擊目前還是存在的。。。
HTTPS 中間人降級攻擊,本質上就是把流量中的 https:// 替換成 http:// 。是以又稱 -1s 攻擊~
2018-7-26
由于大部分使用者都不會開啟浏覽器 Do Not Track,是以少數開了的使用者反而成了另類,被用于浏覽器指紋特征了。。。
2018-7-20
思考題:在 JS 中用 0 0 0 0 四個常量計算 24。隻能用符号,表達式越短越好~
目前已知最短的答案 14 字元。
https://jsfiddle.net/qLo2jg7x/2018-6-6
BitInt 出現後,不用死循環也能實作 CPU 100% 的效果了。一個 2 層幂塔就能卡死浏覽器~
9n ** 9n ** 9n > 0
為什麼這裡要加 > 0 的判斷,因為
9 ^ 9 ^ 9 ≈ 4.28 x 10^369693099
這個數字,光是位數就有 369,693,099 之多,相當于控制台要輸出一個 300 多兆的字元串!是以為了不在輸出時卡死,于是加了個判斷。
(事實上基本等不到字元串輸出那步)
2018-5-22
nodejs 惡作劇:給系統建立一個叫 node_modules 的使用者,然後 npm install 就無法使用了~~~
如果真遇到項目檔案夾之外有 node_modules 的話,隻要在 npm install 時加上參數 --prefix path 就可以強制指定 node_modules 的路徑。
2018-5-21
之前遇到個網站 WAF 的 JS 腳本,代碼經過多次動态混淆。
為了防止被人調試,前端不斷執行 debugger 指令,然後檢測執行用時 —— 如果控制台開着,debugger 指令會觸發斷點,用時顯然高出平常。于是 JS 會給後端發送日志,然後 IP 就被網站 ban 了。
setInterval(function() {
var t1 = Date.now();
debugger;
var t2 = Date.now();
if (t2 - t1 > 100) {
console.log('debug detected');
// send_log('ban this ip');
}
}, 500);
簡單示範:
https://codepen.io/anon/pen/rvPYxR?editors=0010當然,在經過幾次 IP 更換後,很快就摸索出了一個超級簡單的規避方案。猜猜是如何實作~
其實非常簡單,禁用調試器斷點功能就可以,比如 Chrome DevTool 的箭頭圖示。
不過想要一次成功,還是需要些小技巧的,畢竟剛打開 DevTool 的時候還是會觸發 debugger 斷下來的:
是以正确的打開方式,應該先随便開一個網頁,打開 DevTool 禁用斷點:
然後再打開想要通路的網頁,這時 debugger 就不會觸發了:
大寫的 αß 服不服~
'αß'.toUpperCase() // "ΑSS"
類似的還有 'ffi'.toUpperCase() === 'FFI'。然而 '嬲'.toUpperCase() !== '男女男' ~
2018-5-21
随着 JS 引擎優化能力的提升,越來越多的性能黑魔法将會消失~
2018-5-15
思考題:定義 x 使得滿足條件判斷,字數越少越好。目前我的答案是 28 個字元,看看有沒有更短的~
const x = _______
const win = ('a' in x) && !('a' in x)
console.log(win) // true
https://jsfiddle.net/r6gk1ob8/ 2018-5-14
思考題:有些 JS 代碼混淆後,會變成 eval(一大坨代碼) 的形式。當然解密也非常容易,把 eval 換成 console.log 就能原形畢露。
下面請思考,如何在「一大坨代碼」中加入陷阱,跟蹤有哪些人把 eval 換成了其他的函數?
https://codepen.io/anon/pen/odMbBX?editors=0010(eval 換成 console.log 即可觸發陷阱)
如何使用 JS 緩解網站 DDOS 的攻擊?
https://yq.aliyun.com/articles/236585大緻原理:網頁多用強緩存(目前是 Service Worker),發生故障時可毫秒級切換流量到 N 個後備節點。網站被打垮也隻影響新使用者,老使用者照樣可以流暢通路~
當然這其中細節問題很多,以後會在
https://github.com/EtherDream/js-anti-ddos中讨論。
2018-5-8
相冊裡翻到個上古時代用
示範:
https://www.etherdream.com/creative/BaiduCube.htmlDXImageTransform.Microsoft.Matrix。當年硬着頭皮用國中數學知識琢磨 Martix 的計算規律,陸續花了幾個月才寫出來~
2018-5-6
思考題:JS 如何自我檢測代碼是否被人修改?
舉個栗子,有個腳本混淆後去除了換行、縮進等格式,并且變量名故意弄得特别長,幹擾分析。這時破解者通常會格式化代碼,然後變量名短化,儲存後再運作分析。是以,腳本如何自我檢測是否被篡改?
分享之前寫的一個 PPT
《前端加密與混淆》,其中提到 JS 如何檢測自身子產品是否被篡改。以及檢測到異常情況後,該如何優雅的讓程式逐漸錯誤,而不是立即崩潰~
2018-5-4
分享曾經折騰的一種 JS 混淆思路:
(function(id, name, age, lang) {
var PTR = arguments
console.log(id, name, age, lang) // 1001 "alice" 20 "en"
PTR[0] = 1002
PTR[1] = 'bob'
PTR[2] = 30
PTR[3] = 'us'
console.log(id, name, age, lang) // 1002 "bob" 30 "us"
})(1001, 'alice', 20, 'en')
把函數中所有的局部變量都定義在形參裡,然後建立一個叫 PTR 的變量(模拟指針)指向 arguments。
之後通過 PTR[數字] 即可讀寫局部變量,而不用對具體變量指名點姓的通路,增加分析難度~
當然,後來 strict mode 普及之後就再沒考慮這方案了。
2018-5-3
現代浏覽器 referrer-policy 的出現,使得大量網站可當圖床使用~
是以 referrer 為空也是一種盜鍊
2018-4-25
思考題:現有一款浏覽器安全插件,會對 performance.now 接口進行 Hook,以降低 JS 擷取到的時間精度,減少邊信道攻擊的風險。
該插件會将如下代碼注入到頁面最先運作(包括架構頁、空白頁等):
(function() {
const obj = performance
const rawfn = Performance.prototype.now
Performance.prototype.now = function() {
let val = rawfn.apply(obj, arguments)
return ((val * 10) | 0) / 10 // 精度降低到 0.1ms
}
})()
下面思考,有哪些方案可繞過該插件的防護,進而擷取到原生的高精度時間。
并且對于這種繞過方案,怎樣改進才能防範?
答案參考「有什麼場合,必須使用 ES6 的 Reflect」的思路。另外,new Event(0).timeStamp 也可以擷取高精度時間。
2018-4-23
記得很久前就有人提過,使用 localStorage 緩存 html、js 存在較大的安全隐患,萬一出現 XSS 可能會導緻惡意代碼長期感染,進而形成 Rootkit。
盡管現在用 localStorage 的已經不多,但類似的緩存方案仍存在。目前最主流的方案是 Cache Storage + Service Worker,不少 PWA 都采用這種緩存方式。然而不幸的是,Cache Storage 同樣存在上述安全隐患 —— 由于「Service Worker」和「頁面」是共享同個 Cache Storage 的,是以一旦頁面修改了 Storage 的資源,同樣會影響 Service Worker 擷取的内容。
我們随便找一個使用 Cache Storage + Service Worker 緩存的網站,幾乎都存在這個問題。在頁面裡修改 Cache Storage 中的某個 JS 内容,之後重新開機浏覽器,惡意代碼仍然生效。
2018-4-19
嘗試用指令 + 寄存器的思路,在 WebAssembly 中操作 JS 和 DOM~
2018-4-18
思考題:上傳檔案的過程中,如果使用者重新整理或關閉頁面,那麼就前功盡棄了。之後使用者還得重新打開檔案選擇框、重新上傳。
下面請思考,如何實作:
1.使用者隻需打開一次檔案選擇框,之後即使重新整理頁面,也無需再選擇檔案,繼續之前的上傳?
2.使用者即使關閉頁面(但未退出浏覽器),檔案仍能持續傳輸一段時間?
2018-4-17
思考題:如何産生這種效果~
(不能重寫 document.cookie,而是真有這麼多重複的鍵值)
2018-4-8
整理檔案時發現過去寫的一個 JS 思考題:用最簡單的辦法讓 console.log(1) 輸出 0。被自己的答案驚呆。。。
寫的不嚴謹,應該說是傳回 0,而不是輸出 0。
2018-3-22
分享一個網站去中心化的探索~
原理:把網站資源上傳到各大圖床、相冊上,前端通過 Service Worker 代理,然後從圖檔中還原出原始資料。于是自己的網站隻需放置一個極小的 HTML 和 JS 檔案,即可享受無限帶寬。
https://fanhtml5.github.io/因為 Service Worker 具有持續性,是以隻要通路過一次,之後就算網站挂了,使用者仍能正常通路 —— 除非所有的備用節點都挂了。(裝上 Service Worker 就去中心了)
此外,這個方案還可用于 DDOS 防禦 —— 網站即使被打垮了,但之前通路過的使用者,仍能通路。
相比傳統 DNS 負載均衡至少有好幾秒的延時,Service Worker 通過 JS 實作節點切換,延時可以精确到 ms 級别;并且 DNS 協定是公開的,很容易周遊對應的 IP,而 JS 則可加上代碼混淆,增加分析的難度。。。
關于前端負載均衡,之前寫的一些思路:
https://yq.aliyun.com/articles/236582打開浏覽器隐身模式,通路
https://fanhtml5.github.io/big-pic.png出現的是個圖檔,但用 curl 通路并不是圖檔。這就是這個方案有趣的地方~
2018-3-17
打開浏覽器 console 會觸發浏覽器加載 js 尾部的 source map url,于是後端就可以收到日志。
并且動态建立的腳本也支援 source map url,是以 url query 裡還可以加上使用者相關的參數,跟蹤哪些人開了控制台~
2018-3-9
控制台 FBI WARNING 惡作劇~
(暫隻支援 Chrome)
2018-3-9
分享跳轉 opener 的另類玩法~
大家知道 Service Worker 可以持續運作一段時間,可以用來挖礦、破解密碼等等。。。不過 XSS 沒法安裝 SW,因為 SW 的腳本必須和頁面同源;iframe 也沒法安裝,因為浏覽器規定隻有首頁面才可以安裝。
是以,唯一可行的就是把 opener (假如存在的話)跳轉到自己網站上,裝完 SW 再自動傳回~
關于 Service Worker 各種玩法,可參考 https://github.com/etherdream/sw-sec
2018-1-25
紅白機遊戲《超級瑪麗》彙編指令重編譯成 JavaScript:
Demo:
https://www.etherdream.com/FunnyScript/smb-js/game.html原理:
https://www.cnblogs.com/index-html/p/6492418.html2017
2017.md