發現Webpack中泄露的api
發現Webpack中泄露的api
已在先知社區發表,轉載請註明出處
1 – 安裝 reverse-sourcemap
需要配置好npm環境 (runoob教程)
使用命令(需要代理) npm install --global reverse-sourcemap
進行安裝
2 – 尋找xxx.js.map
如果有sourcemap的話,在js最後會有注釋:
//# sourceMappingURL=xxxxxxx.js.map
比如這裡我要下載MarketSearch.js.map
(MarketSearch.js
是與站點同名的js,應該是主要的js文件)
- 在開發者工具中搜索
.js.map
(位置1) - 找到
MarketSearch.js.map
所在的js (位置2) - 找到對應的鏈
URL
(位置3)- 一般來說,靜態文件會掛載在當前域名下,但不排除其他站點掛載的情況,所以需要找到對應的
URL
,比如這裡就不同站 - 這裡
MarketSearch.js
的URL
記為//xxx.xxx/mulu/MarketSearch.js
- 一般來說,靜態文件會掛載在當前域名下,但不排除其他站點掛載的情況,所以需要找到對應的
3 – 下載xxx.js.map並獲取所有webpack打包文件
使用curl -O //xxx.xxx/mulu/MarketSearch.js.map
或者直接訪問//xxx.xxx/mulu/MarketSearch.js.map
下載MarketSearch.js.map
使用命令reverse-sourcemap --output-dir ./MarketSearch MarketSearch.js.map
即可獲取所有webpack打包文件
4 – 使用IDE/其他編輯器尋找接口
我這裡使用的是vs code
直接使用全局搜索 左邊側邊欄的搜索圖標,或者ctrl+shift+f
4-1 搜索接口
搜索接口有兩個方法:
一個是借鑒先驗請求的url
,這種情況需要我們可以訪問到某些接口,比如非SSO的登錄
另一個是直接搜索,這種情況大多是我們沒法訪問到當前站點的接口
4-1-1 借鑒先驗請求的url
比如我們訪問的站點xxx.xxx
存在登錄接口,通過嘗試,發現會調用/MarketSearch/api/login
接口
那麼我們可以通過不斷刪減來搜索接口/MarketSearch/api/login
,/api/login
,/login
可以看到,當我們刪減到/api/login
的時候,就可以找到接口對應的代碼
這個接口是可以調用的,但是發現其定義的接口與實際訪問的接口不同(第五部分解釋,這裡使用了動態定義的接口)
4-1-2 直接搜索
直接搜索有兩種方法,根據請求方法,或者猜測命名規則進行搜索
4-1-2-1 根據請求方法搜索接口
接口大多是通過get/post
方法進行訪問的,所以這是一個很好的關鍵詞
通過請求方法,可以搜索到動態定義的接口(第五部分),避免找不到接口的問題。
而且,如果存在請求方法重寫的代碼,通過請求方法搜索可以發現這些代碼的定義。
post
get
4-1-2-1 根據猜測命名規則搜索接口
一般來說,admin
,superadmin
,manage
之類的關鍵詞比較常見
此外,還可以根據站點名,可調用api命名規則,js命名規則進行搜索。這個站點沒有這樣的接口,就不舉例了。
5 – 尋找動態定義的接口
剛好這個站點存在動態定義的接口(直接明文寫在js代碼中的靜態接口相反):MarketSearch/api/login
,上面我們通過搜索,只發現了/MarketSearch/api/user/login
接口,這裡介紹一下如何尋找該接口。
首先搜索login
,可以看到在index.ts
中對登錄進行了定義
查看index.ts
,可以看到這裡定義了用到的視圖,繼續跟蹤Login
視圖,命名為Login_1
,路徑在./Login
打開Login.tsx
,可以看到根據vse_client_1.defaultMainView.Login
視圖,創建了對應的元素,vse_client_1
定義為vse-client
打開vse-client
目錄,尋找defaultMainView
視圖的定義
跟蹤Login
視圖,可以看到api_1
路徑在./api
,且Login
視圖定義了遊客登錄
和用戶登錄
兩個登錄方式,這裡跟蹤用戶登錄
登錄方法
用戶登錄
使用了LoginModal
模態框
跟蹤LoginModal
模態框,可以看到登錄的行為通過yield api_1.api.login(input)
來實現
api_1 = ./api
,input
則是ItemKey
生成的表單中用戶填寫的數據(username & password
)
跟蹤api_1.api.login
大致說一下這裡的邏輯:
-
key是鍵值,比如這裡調用的是
api.login
,則key === login
-
對於每一個
vse_share_1.Api
定義的接口
-
如果傳入的
key
與其中一個接口相同,且不為constructor
(通過prototype
原型讀取,所以需要排除構造函數),則向下繼續 -
login
傳入__awaiter_
-
通過
axios_1.default.post(`/${NAMESPACE}/${vse_share_1.ShareConfig.apiPrefix}/${key}`, args)
發起請求-
${NAMESPACE} === MarketSearch
-
查看命名空間的定義
-
跟蹤
../share
-
-
${vse_share_1.ShareConfig.apiPrefix} === api
- 跟蹤
vse-share
,尋找ShareConfig
- 跟蹤
-
${key} === login
-
args === input
,即,由ItemKey
生成的json{username:"xxx",password:"xxx"}
-
這種情況下,通過拼接預定義參數和傳入的api
名稱,動態生成url
路徑,避免了靜態存儲api
路徑,使得尋找api
接口需要花費的精力大大提升。(web安全狗流淚)