1. 程式人生 > >12306 搶票系列之只要搞定RAIL_DEVICEID的來源,從此搶票不再掉線(上)

12306 搶票系列之只要搞定RAIL_DEVICEID的來源,從此搶票不再掉線(上)

鄭重宣告:
本文僅供學習使用,禁止用於非法用途,否則後果自負,如有侵權,煩請告知刪除,謝謝合作!

開篇明義

本文針對自主開發的搶票指令碼在搶票過程中常常遇到的請求無效等問題,簡單分析了 12306 網站的前端加密演算法,更準確的說,是探究 RAIL_DEVICEID 的生成過程.

因為該 cookie 值是搶票請求的核心基礎,沒有它將無法正確傳送請求,或者一段時間後就會到期失效需要重新獲取,或者明明更改了瀏覽器使用者代理(navigator.userAgent)標識卻還是被限制訪問...

因為它並不是真正的客戶端標識,只是迷惑性戰術,瀏覽器唯一標識其實是 RAIL_OkLJUJ 而它卻被 12306 網站設計者故意沒有新增到 cookie ,因此造成了很強的欺騙性,程式設計真的是一門藝術!

你以為你的爬蟲已經可以正常模仿瀏覽器,殊不知,只要沒搞懂誰才是真正的瀏覽器標識,那麼再怎麼換馬甲也難逃造假事實.

上圖展示了 RAIL_OkLJUJ 的存在位置,可能是為了相容市面上絕大數瀏覽器,也可能是為了聯合各種前端快取技術作為特徵碼,總是除了 cookie 之外,RAIL_OkLJUJ 存在於 Local Storage , Session Storage , IndexedDBWeb SQL 等.

值得注意的是,cookie 中故意沒有設定 RAIL_OkLJUJ ,如果清空全部快取後再次重新整理網頁,你就會發現 RAIL_DEVICEID 已經發生變化了而 RAIL_OkLJUJ

依舊沒變!

下面簡單驗證一下說明誰才是真正的瀏覽器唯一標識:

  • step 1 : 複製當前獲取到的 RAIL_DEVICEIDRAIL_OkLJUJ 的值

開啟控制檯(Console),通過 js 程式碼方式取出本地儲存(localStorage) 的值:

localStorage.getItem("RAIL_DEVICEID");

localStorage.getItem("RAIL_OkLJUJ");

控制檯會立即返回該值,接下來需要手動複製到其他地方等待和第二次結果作比較.

但是程式設計師總是喜歡能偷懶就偷懶,手動複製也懶得複製怎麼辦?

當然,繼續使用js 程式碼複製了啊!

copy('雪之夢技術驛站歡迎您的訪問,https://snowdreams1006.cn');

比如這句程式碼就會把文字'雪之夢技術驛站歡迎您的訪問,https://snowdreams1006.cn'複製到剪貼簿,接下來選擇文字編輯器右鍵貼上就能看到效果啦!

所以改造一下程式碼就能複製第一次訪問 12306 網站獲取到的 RAIL_DEVICEIDRAIL_OkLJUJ 的值.

copy("RAIL_DEVICEID:::"+localStorage.getItem("RAIL_DEVICEID"));
// RAIL_DEVICEID:::E5BDkKrPkZ6nuZruqUj9-3lUG1LBM7t9aTDbZwFSdrboaFG6odrWZ9yuphnas4Jwq5E_FXIwwqlRoSXFbJULUiBNwNGt61Ow6Zv0GFXRABipaeDJJ0Ub7G2g_B_aGwMF5DNZ5KJR4eWVl-P3zSHGKbczLB3WN0z-

copy("RAIL_OkLJUJ:::"+localStorage.getItem("RAIL_OkLJUJ"));
// RAIL_OkLJUJ:::FGFOJ75VdD8dQc2yh3yTJf2RBWES6uGI
  • step 2 : 等待 5 min 後再次獲取 RAIL_DEVICEIDRAIL_OkLJUJ 的值
copy("RAIL_DEVICEID:::"+localStorage.getItem("RAIL_DEVICEID"));
// RAIL_DEVICEID:::VUye37EEUdGHgrpJGo9J95hWMNSIUFPeYBjabDgCiYJbQIr53iVzIPQJwcLhbijL4OyPVGmzolsVEK8Pw7_DG_oPrUDpfbnRe7HvMWMJvU2MAbk-7EwNEePAlpnVb9QVZz4dtOUSCRVbS2zlwgS0xe2BOThpR9oy

copy("RAIL_OkLJUJ:::"+localStorage.getItem("RAIL_OkLJUJ"));
// RAIL_OkLJUJ:::FGFOJ75VdD8dQc2yh3yTJf2RBWES6uGI

或者清空網站 cookie 後再次重新整理當前網頁,總之就是想辦法觸發瀏覽器再次執行相關邏輯重新生成 RAIL_DEVICEIDRAIL_OkLJUJ .

  • step 3 : 對比第一次和第二次獲取到的 RAIL_DEVICEIDRAIL_OkLJUJ 的值
RAIL_DEVICEID:::E5BDkKrPkZ6nuZruqUj9-3lUG1LBM7t9aTDbZwFSdrboaFG6odrWZ9yuphnas4Jwq5E_FXIwwqlRoSXFbJULUiBNwNGt61Ow6Zv0GFXRABipaeDJJ0Ub7G2g_B_aGwMF5DNZ5KJR4eWVl-P3zSHGKbczLB3WN0z-

RAIL_OkLJUJ:::FGFOJ75VdD8dQc2yh3yTJf2RBWES6uGI

RAIL_DEVICEID:::VUye37EEUdGHgrpJGo9J95hWMNSIUFPeYBjabDgCiYJbQIr53iVzIPQJwcLhbijL4OyPVGmzolsVEK8Pw7_DG_oPrUDpfbnRe7HvMWMJvU2MAbk-7EwNEePAlpnVb9QVZz4dtOUSCRVbS2zlwgS0xe2BOThpR9oy

RAIL_OkLJUJ:::FGFOJ75VdD8dQc2yh3yTJf2RBWES6uGI

顯而易見,肉眼直接就能看出兩次請求時 RAIL_OkLJUJ 的值並沒有變化而 RAIL_DEVICEID 的值很大可能會發生改變.

因此,RAIL_DEVICEID 應該並不是瀏覽器唯一標識,而 RAIL_OkLJUJ 才是真正的唯一標識!

本文並不適合全部讀者,如果你屬於以下情況之一,那麼本文對你絕對幫助甚多,否則對你來說只能算是浪費生命.

  • 適合對自主搶票或者指令碼搶票有需求的天涯遊子
  • 適合擁有一定 web 前端開發相關知識的開發者
  • 適合耐得住寂寞能夠獨自研究加密演算法的孤獨人

最後的核心前提是有網,當然WiFi更佳,否則流量真的吃不消啊!

故事背景

獨在異鄉為異客 每逢佳節要搶票
手動自動一起上 時常掉線心好傷
動手實踐出真理 原來身份是唯一
想要封你沒商量 只能動手來偽裝
加密請求在前端 後端返還控制權
還原演算法改身份 穩定搶票不擔心
多種途徑齊上陣 車票速速快現身

不知道你是否遭遇過一票難求的困境,儘管網路上關於第三方工具的加速包是否加速有過闢謠,但是每逢節假日總是會遇到搶不到車票的問題,大部分人還是會選擇買個心理安慰吧!

目前為止,12306 官方線上售票渠道僅僅包括 12306 網站以及手機 app 客戶端,因此市面上流行的第三方搶票軟體均為非正常途徑,而這些第三方渠道中最簡單的實現方式應該就算是爬蟲技術了.

不論是網頁端還是手機端,統統稱為客戶端,客戶端的作用僅僅是傳聲筒,真正負責執行命令的人就是服務端.

當你提交購票需求時,客戶端會把這些車票資訊一起打包傳送給服務端,如果服務端有票的話,那麼有可能就會返回給客戶端成功資訊,恭喜你訂票成功.

但是儘管有票也不一定會給你,唯一確定的是無票一定會失敗,總之不管結果如何服務端和客戶端總是按照既定的約定協議在默默交流著.....

儘管官方渠道最可靠也最準確,可官方也還是沒能給你買到車票啊!

所以想要搶票還是得親自動手,不能完全依靠官方,這裡就誕生了爬蟲技術來冒充客戶端,想要成功騙過服務端就要先了解真正的客戶端到底有哪些特徵?

由於本文篇幅有限,暫時不做關於搶票方面的相關論述,直奔重點,講解 RAIL_DEVICEID 的請求過程,帶你一步一步還原 12306 網站的前端加密演算法的實現邏輯!

效果預覽

在瀏覽器控制檯執行 chromeHelper.prototype.encryptedFingerPrintInfo() 方法時會計算真實瀏覽器資訊,如果發現計算結果中的 value 值和真正請求 https://kyfw.12306.cn/otn/HttpZF/logdevice 的 hashcode 值相同,那麼恭喜您,說明 12306 相關演算法還沒更新,如果不相同估計演算法又稍微調整了!

事實證明,12306 演算法雖然在變但都是小打小鬧,根本沒有傷筋動骨,所以自己動手改改又能滿血復活了喲!

{
  "key": "&FMQw=0&q4f3=zh-CN&VPIf=1&custID=133&VEek=unknown&dzuS=0&yD16=0&EOQP=c227b88b01f5c513710d4b9f16a5ce52&jp76=52d67b2a5aa5e031084733d5006cc664&hAqN=MacIntel&platform=WEB&ks0Q=d22ca0b81584fbea62237b14bd04c866&TeRS=777x1280&tOHY=24xx800x1280&Fvje=i1l1o1s1&q5aJ=-8&wNLf=99115dfb07133750ba677d055874de87&0aew=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36&E3gR=9f7fa43e794048f6193187756181b3b9",
  "value": "owRJc8M4EkFMvcTkzibRFJoDSkUKCx6N9ictZIJLIeY"
}
  • step 1 : 使用 Chrome 瀏覽器開啟 12306 網站並清空該站點全部快取資料.

請確保當前正在使用的是谷歌 Chrome 瀏覽器,IE和 firefox 等瀏覽器暫未測試.

  • step 2 : 手動清空 window.name 屬性,保證瀏覽器處於首次開啟 12306 網站狀態.

因為非首次載入會攜帶上一次的請求資訊,不方便學習驗證,經過分析試驗發現歷史狀態還儲存在 window 物件的 name 屬性,因此僅僅清空快取還不夠,還需要手動清空 name 屬性的值.

  • step 3 : 強制重新整理當前頁面並保持記錄請求資訊,過濾請求型別 js ,找到 /otn/HttpZF/logdevice 請求.

在找到該請求儲存查詢引數名為 hashCode: owRJc8M4EkFMvcTkzibRFJoDSkUKCx6N9ictZIJLIeY ,方便和之後的計算方式生成的結果做對比.

除了查詢請求資訊外,更為重要的是檢視響應資訊,當初次請求 /otn/HttpZF/logdevice 時除了返回過期時間 expdfp 裝置資訊之外,還會返回 cookieCode 裝置唯一標識.

如果等到過期時間或手動清空站點快取後,/otn/HttpZF/GetJS 指令碼中的相關邏輯會再次發起 /otn/HttpZF/logdevice 請求,那時候的響應內容再也沒有 cookieCode 引數了.

讓我們再好好看一看初次請求的響應資訊吧!

callbackFunction('{"exp":"1581948102442","cookieCode":"FGHcXsVmjf3oV0zm5qTDPFt-VcNhuDA-","dfp":"QNCYH1J5E9M7rl97uo_PUR1OSwRTcCe1xdnbX7h2V6Ewcq6kML0qzXD5y11rLv3FPX1ndOnhL_bjVkwwgtWTsHMFums60_4H9Lr-vJzJGq4tkaUEGfRNXN9IJlvptReSBa5PP7N5gxpSOBo-YlF5Ac98f-YlNlxi"}')

如果將 callbackFunction() 回撥函式去掉,不難發現其實返回資料是 json 格式,格式化後發現響應內容如下:

{
    "exp": "1581948102442",
    "cookieCode": "FGHcXsVmjf3oV0zm5qTDPFt-VcNhuDA-",
    "dfp": "QNCYH1J5E9M7rl97uo_PUR1OSwRTcCe1xdnbX7h2V6Ewcq6kML0qzXD5y11rLv3FPX1ndOnhL_bjVkwwgtWTsHMFums60_4H9Lr-vJzJGq4tkaUEGfRNXN9IJlvptReSBa5PP7N5gxpSOBo-YlF5Ac98f-YlNlxi"
}

這裡不得不佩服 12306 的設計思路了,故佈疑陣,當你誤以為自己已經更新了 RAIL_DEVICEID 的值,實際上 cookieCode 的值才是唯一標識而它恰恰沒有設定到 cookie 中去,僅僅作為本地快取保持了,用於再次請求 RAIL_DEVICEID.

  • step 4 : 複製原始碼實現到控制檯,輸入 chromeHelper.prototype.encryptedFingerPrintInfo() 獲取請求 /otn/HttpZF/logdevice 的查詢引數,提取出其中的 value 值和真正的請求引數作對比.

假設真正請求引數 hashcode 的值已設定成變數,chromeHelper.prototype.encryptedFingerPrintInfo().value === hashcode 返回結果 true 說明覆現演算法實現還在正常執行,否則很可能是相關演算法又更新了!

直奔重點

如果你正在學習自動搶票或者打算研究如何自動搶票,那麼我可以負責任得告訴你,RAIL_DEVICEID 的值絕對是繞不過去的坎,堪稱 12306 反爬蟲技術的最精華手段!

現在目標已經鎖定,趕緊動手和我一起去探究 12306 到底是如何處理 RAIL_DEVICEID 的值吧!

無痕模式下訪問網站

眾所周知,谷歌 Chrome 瀏覽器是程式設計師專屬的瀏覽器,是因為提供了強大的開發除錯能力,簡單網站請求甚至根本不需要藉助第三方專業的抓包工具就能獨立完成分析整過程.

如果你還沒有聽說過 Chrome 瀏覽器或者正在使用其他瀏覽器,那麼建議你先自行下載最新版 Chrome 瀏覽器,和文章使用一樣的工具有助於順利復現相關步驟,否則遇到莫名奇怪的問題只能自己研究了.

首先開啟 Chrome 瀏覽器的無痕模式,處於無痕模式最大的特點就是不會儲存 cookie,在一定程度上對目標網站而言是新使用者(主要指的是新的客戶端終端).

輸入 12306 官網後,開啟開發者控制檯(F12或右鍵檢查),選擇網路(network)選項卡,確保一直處於監聽網咯請求並實時記錄狀態.

具體而言,最左邊的監聽狀態圓心是紅色,保持日誌(Preserve log)的複選框已勾選,禁用快取(Disable cache) 的複選框已勾選,這三者是分析所有網路請求的基礎.

準備工作就緒後開始完整走一遍購票流程,即從首頁進入登入頁,登入並買票等過程,請求步驟越完整可提供分析的資料越多,也就基本上不會遺漏重要步驟,離真相越逼近.

凡是涉及到登入操作,建議先故意輸出錯誤的賬號密碼等資訊,這樣有利於登入成功後重定向次數過多而導致無法找到之前的登入請求,如果網路(network)選項卡中的保持日誌(Preserve log)的功能沒有開啟的話,這一現象將會更加嚴重!

再次輸入正確的登入資訊成功登入後進行買票行為等操作,但是無需付款,只要正常操作到下單完成即可視為整個購票流程.

下單成功後整個購票流程已經基本完成,接下來開始全域性搜尋關鍵字 RAIL_DEVICEID 檢視在哪裡生成又在何處使用?

全域性模糊查詢關鍵字

現在整個購票流程基本上已經完成,接下來開始全域性搜尋全部請求中是否包含關鍵字 RAIL_DEVICEID 吧!

首先開啟網路(network)選項卡,從左往右數第四個放大鏡圖示就是搜尋功能,輸入搜素關鍵字 RAIL_DEVICEID 會過濾符合條件的網路請求.

不搜不要緊,一搜一大把,只能看出來大部分網路請求都會自動攜帶該 cookie,反而淹沒了到底是哪個網路請求生成的 cookie?

所以必須想辦法精確搜尋,過濾出生成該 cookie 的網路請求,所以接下來的問題就變成了如果 RAIL_DEVICEID 屬於後端直接設定的行為,那麼這樣的網路請求應該長啥樣的?

最好的學習就是模仿,假設並不知道真實的設定過程如何,但是我們可以檢視其它 cookie 的設定過程啊!

同樣地,在網路(network)選項卡選擇第三個過濾器漏斗圖示,展開網路請求型別,大致分為 All|XHR|JS|CSS|Img|Media|Font|Doc|WS|Manifest|Other等型別.

簡單說一下網路請求型別的相關含義,整理出表格直觀感受一下:

型別 名稱 描述 程式碼
XHR XHR adn Fetch ajax非同步請求 X-Requested-With: XMLHttpRequest
JS Scripts js指令碼 Sec-Fetch-Dest: script
CSS Stylesheets css樣式 Sec-Fetch-Dest: style
Img Images 圖片 Sec-Fetch-Dest: image
Media Media 音視訊媒體 Sec-Fetch-Dest: audio
Font Fonts 字型 Sec-Fetch-Dest: font
Doc Documents html文件 Sec-Fetch-Dest: document
WS WebSockets 長連線通訊 暫無
Manifest Manifest 版本檔案 暫無

由於 12306 暫未包括後兩種請求型別,所以無法判斷該請求有什麼特點,除了 ajax 非同步請求外,其餘型別的網路請求都是通過請求頭 Sec-Fetch-Dest 屬性標識的,當然設定瀏覽器的 cookie 也不例外,只不過大多數是通過服務端進行設定的,也就是網路請求的響應頭標誌瞭如何設定 cookie 的行為.

在前端 web 開發的過程中並不是一上來就前後端分離的,很長一段時間內前端頁面也是由後端人員完成的,因此好多網站至今為止還保留著新舊交替的痕跡.

在上述網路請求型別中,最能體現這種變化特點就是 XHR 和 Doc 請求,XHR的常見封裝實現 之一就是風靡全球的 ajax 非同步請求,用於實現無重新整理區域性更新網頁內容,而 Doc 是文件型別,無論是直接輸出原生 html 還是使用模板技術動態渲染頁面,最終輸出展現結果一律是 html 文件,這一類的網路請求最容易設定 cookie 之類的請求,體現了上一代技術的一貫風格,恨不得一個人一次性把全部的活都幹完!

但是隨著技術的發展進步舊技術暴露的問題越來越多,引起了包括開發者在內的業內重視,各大企業已經逐步開始轉變,也就是各司其職,物盡其用.

總結來說,XHR 和 Doc 有如下特點:

  • XHR 請求的資料絕大多數工作是在前端方面完成的,後端把相關資料返回給前端介面呼叫者,前端取到資料後進行業務組裝展現.
  • XHR 請求絕大多數是非同步ajax 請求,優點是當前頁面不需要重新整理就能看到最新內容,缺點是一旦涉及到相互依賴的業務就會出現請求等待噩夢.
  • XHR 請求是又前端發起也就是瀏覽器主動發出給後端,等後端伺服器返回資料後繼續由前端完成相關業務,這部分資料傳輸量極少但非常重要.
  • Doc 請求大多數是後端在控制,方便設定各種頁面元素的表現形式,但是也不排除前端使用相關的模板引擎結合 XHR 資料在控制生成文件.
  • Doc 請求設定包括 cookie 在內的一系列網路行為,轉發和重定向更是許可權控制的常用做法.

下面我們已包括 RAIL_DEVICEID 關鍵字的網路請求,簡單感受一下兩者的差異性.

XHR 請求重點在於如何請求資料和接收資料,主要體現在 Request Data 和 Response Data 兩方面,至於請求頭一般都是預設設定.

Doc 請求的重點就不一樣了,絕大多數請求就是輸入網址後自動跳轉頁面,因而關注的重點應該放在請求頭和響應頭資訊上,因為 cookie 的值就是通過請求頭進行傳送到後端伺服器,後端如需新增或修改 cookie 值就是通過響應頭進行設定的.

柿子還要先捏軟柿子,現在無法判定 RAIL_DEVICEID 到底是服務端直接設定還是客戶端自行設定的,而客戶端的行為不太直觀,所以相對而言還是先捏服務端軟柿子吧!

回顧剛才講解的 Doc 網路請求,不難發現設定 cookie 的行為程式碼類似如下:

Set-Cookie: JSESSIONID=D4CE095F5A21B38DF3389070F1E01FE6; Path=/otn

現在找到了學習物件,開始模仿查詢類似請求的關鍵字應該是: Set-Cookie: RAIL_DEVICEID=

查無結果!

一般情況下出現無結果很可能是以下原因之一:

  • 恭喜您,真的查無結果,可以換條思路繼續探索了.
  • 很遺憾,當前網路請求資料不足剛好缺失符合條件的請求.
  • 日了狗,操作不當誤輸多餘符號或者本是關鍵字搜尋實際上卻開啟了正則匹配等

所以逐一排查以上原因,首先考慮換一個關鍵字 Set-Cookie: JSESSIONID 能否查找出相應的結果.

事實勝於雄辯,查詢過程並沒有任何問題而是查詢結果真的不存在,如此一來一次性排查兩個原因,那麼很有可能生成邏輯在於前端而非後端.

接下來只能在眾多請求中碰碰運氣尋找前端到底是在何處生成的 RAIL_DEVICEID ,然而請求眾多還是要稍微講究一下策略方向的.

既然是前端在控制 cookie 的生成邏輯,那麼很有可能是某個 js 檔案在起作用,當然也不排除其他型別的檔案有操作瀏覽器行為的能力.

因此,通過分析進一步縮小範圍:在請求型別為 JS 的網路請求中查詢包括關鍵字 RAIL_DEVICEID 的全部請求.

理想很豐滿,現實太骨感,本以為選中 js 再搜尋關鍵字能夠一起生效,結果並沒有,請求型別依舊沒有過濾出去,還是一大片的請求!

同時隨便選中任意請求可以看到此時網路選項卡搜尋匹配大結果其實是請求頭這些基本資訊,應該並沒有包括 js 或者 doc 原始碼,方向錯了,走再多路也是浪費時間.

雖然我不知道你從哪裡來,中間經歷了什麼,但是我知道你的最終歸宿一定會落到網路檔案系統.

Chrome 瀏覽器除了可以看出網路請求也能看到最終呈現給使用者的檔案系統,既然中間過程找不到你,那麼我直接到目的地去搜索吧!

開啟原始碼(Source)選項卡,整個面板大致分為三部分,左側檔案數,中間檔案區,右側除錯區.

其中左側的檔案結構可以清楚看到當前所處的層級結構,有利於快速掌握專案輪廓.右側的除錯區針對心中有想法但還不確定是否正確提供了非常好的驗證工具,除錯別人的程式碼就如本地開發那樣邊預言邊驗證.

中間的檔案區域面積最大,功能自然也不能太弱,選中左側具體檔案後可以顯示原始碼,方便檢視,進而去除錯驗證心有所想.

所以問題來了,這一切的一切都要源於心有所想才能有行動,那麼應該去哪裡搜尋包括關鍵字 RAIL_DEVICEID 的檔案呢?

一般而言,良好的使用者體驗是不需要告訴你使用者手冊的,給你一大堆詳盡的說明文件也未必會耐得住去看一篇,先用用再說!

人生苦短,不要浪費太多時間放在無聊的事情上面,簡短的三行提醒富含哲理性,第一行告訴你怎麼開啟檔案,第二行告訴你如何執行命令,第三行告訴你如何操作實現什麼效果.

如果三行程式碼還不足以解決你的問題,閱讀更多自己慢慢琢磨說明文件吧!

當然,這裡和在檔案系統中查詢包含關鍵字 RAIL_DEVICEID 的需求最為接近的應該就是第二行,執行命令了,那就試試看吧!

輸入搜尋 search 後果然彈出了相關搜尋命令,於是點選開發工具(DevTools)後出現了搜尋框,順理成章輸入關鍵字 RAIL_DEVICEID 進行搜尋了啊!

終於等到你,還好我沒放棄,你就是我的唯一,看樣子和 RAIL_DEVICEID 有關的處理邏輯全部都在這麼一個 js 檔案裡,看你還往哪裡跑!

直搗黃龍還往哪裡跑

找到該檔案後點擊檢視,紅藍黑密密麻麻一大片js 程式碼,絕對不是給人看的而是給機器看的,想要給人閱讀還需要美化一下,將原始碼醜化混淆成難以閱讀的程式碼也是防止他人偷窺複製拷貝自己的勞動成果,同時也能減少檔案大小,加速網路傳輸資料,讓你的網站速度更快一些.

點選中間區域的左下角格式化圖示進行美化程式碼,然後在檔案中搜素關鍵字 RAIL_DEVICEID 定位到具體程式碼.

非常人性化的是,搜尋功能是通用的快捷鍵 Ctrl + F,現在定位到具體程式碼,截圖留念下,接下來才是真正考驗技術的時刻!

$a.getJSON("https://kyfw.12306.cn/otn/HttpZF/logdevice" + ("?algID\x3drblubbXDx3\x26hashCode\x3d" + e + a), null, function(a) {
    var b = JSON.parse(a);
    void 0 != lb && lb.postMessage(a, r.parent);
    for (var d in b)
        "dfp" == d ? F("RAIL_DEVICEID") != b[d] && (W("RAIL_DEVICEID", b[d], 1E3),
        c.deviceEc.set("RAIL_DEVICEID", b[d])) : "exp" == d ? W("RAIL_EXPIRATION", b[d], 1E3) : "cookieCode" == d && (c.ec.set("RAIL_OkLJUJ", b[d]),
        W("RAIL_OkLJUJ", "", 0))
})

本地備份js方便復現

既然已經找到關鍵檔案,自然需要留存快照進行存檔操作,否則哪一天檔案更新了都不知道哪裡發生變化了,難不成還要從頭再分析一遍,我選擇差量更新而不是全量覆蓋!

選中原始檔右鍵彈出選單,選擇任意一款喜歡的方式複製原始檔到本地留作學習備份,準備工作就緒後準備大幹一場.

未完待續

由於篇幅有限,一篇博文不得不分成三部分,對此造成的不良體驗,還請見諒,如需閱讀剩餘部分,關注雪之夢技術驛站不迷