造合法請求全記錄)
前陣子拿到一套很有意思的安全賽題代號叫“wsgsig secdd-challenge”。這套題目表面上是給某出行平臺的內(nèi)部安全挑戰(zhàn)賽準備的實際上拆開來看它把真實業(yè)務(wù)里最常見的三類問題——簽名算法被逆向、加密參數(shù)被繞過、請求重放——全都揉到了一起。我花了兩天時間完整走了一遍從黑盒分析到最終構(gòu)造合法請求拿結(jié)果的流程踩了不少坑也沉淀出一些通用打法。這篇文章就把整個拆解過程、關(guān)鍵原理、實操步驟和排查經(jīng)驗完整記錄下來希望能給正在研究接口安全、簽名校驗或者準備類似CTF/實戰(zhàn)演練的同學一些參考。1. 賽題概況與整體思路拆解1.1 賽題背景與核心需求先說這個題目的結(jié)構(gòu)。整套環(huán)境模擬的是一個帶有簽名校驗機制的Web服務(wù)客戶端向服務(wù)端發(fā)起請求時需要攜帶一組由特定算法計算出的簽名參數(shù)服務(wù)端收到請求后會重新計算簽名做比對不一致就直接拒絕。題目名稱里“wsgsig”可以理解為某種Web服務(wù)簽名機制的代號“secdd”則指向安全防護與加解密相關(guān)的場景。這種設(shè)計在真實業(yè)務(wù)里太常見了。現(xiàn)在但凡有點規(guī)模的系統(tǒng)對外暴露的接口基本都不會裸奔——要么有簽名校驗要么有加密傳輸要么兩者都有。簽名的作用是保證請求參數(shù)在傳輸過程中沒有被篡改加密的作用是保證數(shù)據(jù)內(nèi)容不會直接被第三方讀取。這套題目等于把這兩個問題塞進了一個可實操的環(huán)境里讓我能在“合法請求長什么樣、簽名怎么算的、加密怎么解開的”這幾個問題上反復(fù)驗證自己的判斷。我在拿到題面之后的第一反應(yīng)不是直接去看代碼或者跑掃描器而是先想清楚這題目究竟想考什么。答案其實很明確簽名機制的分析能力和構(gòu)造合法請求的能力。前者考驗?zāi)隳懿荒軓暮诤谢蛘邘Р糠中畔⒌幕液协h(huán)境中還原出簽名的生成邏輯后者考驗?zāi)隳懿荒馨迅倪^的參數(shù)、新的時間戳、正確的簽名組合成一次能被服務(wù)端接受的請求。從攻防兩端的角度來看這套能力在真實業(yè)務(wù)里就是做接口安全測試的底層基本功。1.2 為什么這類簽名校驗題目值得花時間深挖我遇到過不少人覺得簽名校驗就是加個密、算個哈希沒什么技術(shù)含量。但真正落到實操層面你會發(fā)現(xiàn)它牽扯到的問題遠比想象中復(fù)雜。首先是簽名不等于加密。簽名解決的是“參數(shù)是否被篡改”的問題加密解決的是“內(nèi)容是否被偷看”的問題。很多人在分析時會在這兩個概念上繞暈導致走了彎路。比如有些題目表面上給你一堆密文實際上簽名用的只是拼接后的一段明文參數(shù)加密只是用來傳輸對稱密鑰的殼。其次是簽名算法的可還原性。業(yè)界常用的簽名方案無外乎幾種MD5家族、HMAC-SHA系列、以及基于非對稱加密的數(shù)字簽名。每種方案的逆向難度不同。MD5拼接參數(shù)的簽名很容易通過輸入輸出對比猜出規(guī)則HMAC要是有固定的密鑰還行如果密鑰是從服務(wù)端動態(tài)下發(fā)的就得先解決取密鑰的問題RSA/ECDSA這類非對稱簽名則會直接給逆向者出難題。這套題目把幾種可能性都覆蓋了一部分正好用來系統(tǒng)練習。再就是時間戳與隨機數(shù)的對抗。為了防止重放攻擊簽名中基本都會包含時間戳甚至隨機數(shù)。這意味著你就算完全逆向出了簽名算法如果請求里的時間戳是舊值簽名照樣過不了。這個細節(jié)卡住了很多半途而廢的人也是后面我要重點講的部分。1.3 整體解題思路地圖我自己的解題流程分成五個階段這張圖即使換一道類似題目也完全通用環(huán)境與信息收集部署好本地環(huán)境確認目標地址、接口列表、請求樣例拿到一份含簽名的合法請求作為分析樣本。定位校驗邏輯通過修改單個參數(shù)觀察響應(yīng)差異找出哪個部分是簽名校驗、哪個部分是加密字段、哪個部分是防重放的時間戳。逆向簽名過程結(jié)合已知參數(shù)樣本和響應(yīng)反饋推斷簽名生成規(guī)則。必要時抓取加密JS、反編譯二進制或者用輸入輸出對做差分分析。構(gòu)造合法請求按還原出的算法用新時間戳和新參數(shù)重新計算簽名組裝請求并驗證通過。總結(jié)與自動化寫個腳本把整個簽名計算和請求發(fā)送流程固化下來方便后續(xù)批量測試和復(fù)用。后續(xù)的章節(jié)我會按這個順序展開重點講每一步“為什么要這么做”以及“怎么判斷自己的方向是對的”。2. 核心機制解析與前置知識儲備2.1 簽名算法的常見結(jié)構(gòu)與識別技巧在拆解這套題的過程中我對接口簽名機制的整體形態(tài)做了系統(tǒng)梳理。大多數(shù)簽名邏輯都可以抽象成三層結(jié)構(gòu)第一層是參與簽名的參數(shù)集合。有些實現(xiàn)會把所有請求參數(shù)都拼進去有些只選擇除簽名本身以外的固定幾項。判斷哪些參數(shù)參與簽名最樸素的方法是把某個參數(shù)的值改掉看簽名是否還通過。如果通過說明該參數(shù)沒有參與簽名如果不通過說明在簽名集合內(nèi)。第二層是參數(shù)的組織方式。常見的組織方式包括按字典序排序后拼接a1b2c3直接按固定順序拼接成字符串1|2|3拼接后再加上鹽值或密鑰secretKey queryString嵌套JSON序列化后參與計算第三層是散列或加密算法。這是最容易通過特征判斷的部分——MD5是32位十六進制、SHA1是40位十六進制、SHA256是64位十六進制、HMAC在輸出長度之外沒有明顯特征但可以通過源碼或行為推斷、AES則有填充和初始化向量的問題。如果你想快速判斷算法就把同一組參數(shù)多提交幾次觀察簽名長度和字符集。64位且為十六進制字符大概率是SHA25632位則大概率是MD5但也存在SHA256截斷或者自定義散列的可能。實踐中最穩(wěn)妥的方式還是拿到足夠多的輸入輸出對直接拿常見算法套算對得上就是它。2.2 防重放機制時間戳、nonce與服務(wù)端校驗簽名本身防的是篡改但如果沒有防重放措施攻擊者拿到一個合法請求后可以無限次重復(fù)提交。所以絕大多數(shù)簽名方案都會加入時間戳或一次性隨機數(shù)nonce。時間戳的校驗邏輯一般是“當前時間戳 - 請求時間戳”的絕對值不能超過某個閾值比如300秒。有些嚴格的服務(wù)會直接把這個閾值設(shè)定為60秒甚至更短這種情況下構(gòu)造請求時必須確保時間偏差在允許范圍內(nèi)。如果你在本地測試系統(tǒng)時間和目標服務(wù)器時間相差很大一定要先同步時間。nonce的校驗邏輯一般是服務(wù)端維護最近一段時間的nonce集合使用過的nonce如果再次出現(xiàn)就拒絕。這種情況比時間戳難處理一些因為你需要保證每次請求的nonce是全新的。好在很多實現(xiàn)里nonce可以直接用UUID或者隨機字符串代替。在這套題目里我觀察到時間戳和nonce的配對方式是比較典型的簽名中拼接時間戳請求參數(shù)中附帶時間戳服務(wù)端先校驗時間戳是否新鮮再校驗簽名是否匹配。也就是說直接拿舊請求改簽名的地方是行不通的必須同步更新簽名里的時間戳、請求參數(shù)里的時間戳再重新計算整個簽名。2.3 加密字段的定位與處理思路題目名稱中的“secdd”后半段指向加解密場景。在真實的簽名機制里有些系統(tǒng)會把敏感字段加密后再參與簽名或者對傳輸內(nèi)容做整體加密。這類題目的分析順序我建議是先解密再定位明文參與簽名的部分最后重新計算簽名。有個原則必須記住密文的可識別性。如果密文是Base64編碼的直接解碼就能看到二進制結(jié)構(gòu)如果密文是十六進制字符串長度往往是明文的整數(shù)倍尤其AES這類分組加密算法。分析時需要關(guān)注的不是密文本身而是解密之后得到的明文結(jié)構(gòu)——參與簽名的到底是解密后的明文、還是加密前的原始請求體這兩個是完全不同的路徑。我在這套題里碰到的情況比較直接請求體中的某個字段是經(jīng)過加密的加密后的結(jié)果也參與到了簽名計算中。這種做法看起來很安全——改動一個字符都會導致簽名失效。但反過來想只要逆向出加密邏輯和簽名邏輯構(gòu)造合法請求反而是順理成章的事。3. 實操全過程記錄從黑盒分析到請求偽造3.1 環(huán)境部署與初始信息搜集我習慣在本地跑一套獨立環(huán)境來復(fù)現(xiàn)這類題目這樣既能隨意斷點調(diào)試又不會因為服務(wù)端策略變化而影響分析。題目提供的環(huán)境包含一個后端服務(wù)、一個模擬客戶端客戶端會向服務(wù)端發(fā)起帶簽名和加密參數(shù)的請求。部署完成后第一步不是急著提交亂七八糟的payload而是先抓一個完整請求出來。操作方式很簡單在客戶端點擊某個功能按鈕同時用一個HTTP抓包工具記錄請求內(nèi)容。抓到之后把請求頭、請求體原樣保存一份作為所有分析的基準樣本。這個基準樣本里包含了接口路徑比如/api/order/create和/api/user/info請求頭里的固定字段和動態(tài)字段請求體中的明文參數(shù)、密文字段和簽名字段拿到基準樣本后我對請求體做了一個快速拆分。以其中一個典型請求為例它大致長這樣{ app_id: test_app, timestamp: 1712332800, nonce: a1b2c3d4e5f6a7b8c9d0e1f2, data: U2FsdGVkX1..., sign: 9f2c4b7e6d1a3f8c0b2e4d6a8f1c3e5b }這里timestamp和nonce很直觀data是一串看起來像Base64的密文sign是64位十六進制字符串——和SHA256的輸出長度完全吻合。我先做了兩個測試。第一個測試是把timestamp改成一個明顯過期的時間結(jié)果顯示簽名校驗錯誤說明時間戳參與校驗。第二個測試是把data中的任意一個字符改掉同樣簽名校驗錯誤說明data參與了簽名計算。這個結(jié)果直接確認了我對參數(shù)集合的猜測app_id、timestamp、nonce、data四個字段全部在簽名覆蓋范圍內(nèi)。3.2 定位簽名校驗點與區(qū)分主校驗和輔助校驗很多系統(tǒng)會有兩層左右的校驗邏輯一層是“格式校驗”一層是“簽名校驗”。格式校驗做的事情包括參數(shù)是否齊全、字段格式是否正確、時間戳是否過期簽名校驗做的事情則是重新計算簽名并與請求中的sign字段做比對。這兩層校驗失敗的響應(yīng)往往不同可以利用響應(yīng)差異來區(qū)分當前遇到的是哪一層。我提交了一個時間戳過期的請求服務(wù)端返回的錯誤信息是“timestamp expired”。這說明時間戳校驗發(fā)生在簽名校驗之前或者時間戳被單獨檢查。接著我把timestamp設(shè)置為當前時間把nonce保持不變其他字段也保持不變再次提交這時候錯誤信息變成了“sign invalid”。這個結(jié)果說明簽名比對是在時間戳通過之后才進行的。這個發(fā)現(xiàn)很重要意味著構(gòu)造請求時必須先確保時間戳在有效窗口內(nèi)再去處理簽名問題。還有一個小細節(jié)值得提有些系統(tǒng)的時間戳校驗不會告訴你“過期”還是“非法”而是把時間校驗也塞進簽名校驗的異常信息里導致你分不清到底是時間問題還是簽名問題。解決的辦法就是用“控制變量法”——先把時間戳設(shè)置為當前時間附近的值排除時間因素再排除其他干擾項。3.3 逆向簽名生成過程輸入輸出對與源碼定位簽名算法是整個題目的核心。我在初識樣本中看到的簽名是64位十六進制最像SHA256?,F(xiàn)在要驗證的就是一件事sign SHA256(某種拼接規(guī)則 data值)到底成不成立。驗證步驟是這樣的從基準樣本中拿到app_id、timestamp、nonce、data以及sign。嘗試幾種常見拼接方式比如app_id timestamp nonce datadata nonce timestamp app_idapp_idxxxtimestampxxxnoncexxxdataxxx按字典序?qū)γ糠N拼接結(jié)果計算SHA256哈希與目標簽名做比對。前幾種常規(guī)嘗試都失敗了。這就說明要么拼接規(guī)則里帶了額外鹽值secret_key要么算法不是SHA256要么拼接格式里有隱藏的分隔符。這時我決定去客戶端的代碼里找線索。我打開了模擬客戶端對應(yīng)的前端資源目錄掃描了半天看到一個與簽名相關(guān)的腳本模塊。這個模塊里定義了一個名為generateSignature的函數(shù)內(nèi)部實現(xiàn)是這樣的function generateSignature(params, secretKey) { var keys Object.keys(params).sort(); var parts keys.map(function(k) { return k params[k]; }); var queryString parts.join(); var raw queryString key secretKey; return sha256(raw).hex(); }這套邏輯非常清晰參數(shù)按鍵的字母序排列拼成a1b2這種標準查詢字符串格式最后在結(jié)尾拼上key密鑰整體做SHA256轉(zhuǎn)十六進制輸出。這說明我之前的失敗原因不是拼接規(guī)則錯而是缺了鹽值。只要補上密鑰就能算出正確簽名。但密鑰怎么來的這里藏了一個常見設(shè)計漏洞——客戶端在初始化時從配置接口獲取了這個密鑰而腳本中有一段代碼把密鑰掛載到了全局對象上。我返回到腳本上下文里搜索secretKey的賦值位置很快找到了值sk_live_test_2024_x9k2。這個操作讓我想到了真實業(yè)務(wù)里經(jīng)常出現(xiàn)的問題密鑰寫在JavaScript前端代碼里、寫在Android APK里、寫在配置文件中沒做混淆。理論上客戶端要計算簽名必然會在某個環(huán)節(jié)接觸到密鑰。密鑰放在客戶端讓計算變得可行同時也讓逆向變得可行。3.4 解密data字段一類典型的對稱加密處理解決了簽名算法另一塊硬骨頭是data字段的解密。data的密文以U2FsdGVkX1開頭這個前綴我印象很深——這是CryptoJS在AES加密后附帶Salt信息的特征。具體的格式是Salted__這8個字節(jié)加8字節(jié)Salt后面才是真正的密文。這意味著data字段很可能是用了OpenSSL兼容的AES-128-CBC或AES-256-CBC加密密鑰可以從某個固定的地方獲取。我在腳本里繼續(xù)搜索與加密相關(guān)的函數(shù)調(diào)用發(fā)現(xiàn)了一個encryptData函數(shù)核心邏輯是用AES-CBC模式加密密鑰是32字節(jié)的固定字符串初始化向量則是前16字節(jié)。關(guān)鍵代碼大概是var key CryptoJS.enc.Utf8.parse(32byteFixedKeyStringForAES); var iv CryptoJS.enc.Utf8.parse(16byteFixedIVString); var encrypted CryptoJS.AES.encrypt(plaintext, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });拿到這段實現(xiàn)后解密就只是個順手的操作了。我用Python的pycryptodome庫按同樣的參數(shù)做了解密把data字段還原成了明文。解密后我看到的是一個JSON對象里面包含真實的業(yè)務(wù)參數(shù)比如用戶名、訂單編號、金額等。這里有個非常關(guān)鍵的認知加密的作用是防止業(yè)務(wù)參數(shù)被直接讀取但不改變簽名計算的方式。簽名計算的是加密后的data值不是解密后的明文。如果我構(gòu)造請求時先改了業(yè)務(wù)參數(shù)再用明文去參與簽名一定會失敗。正確的順序是構(gòu)造業(yè)務(wù)參數(shù)明文。用固定密鑰加密得到新的密文。用新密文作為data字段參與簽名計算。提交完整請求。很多人在這里會犯一個迷糊明明解密時用的是密鑰A為什么加密時也可以用密鑰A答案是這就是對稱加密的特性同一個密鑰既可以加密也可以解密前提是你在本地完全復(fù)刻了對端的加密邏輯。3.5 構(gòu)造合法請求參數(shù)更新、簽名重算與請求重放簽名算法、密鑰、加密方式全部確認之后構(gòu)造一個完全合法的請求就變成了流水線作業(yè)。我用Python寫了完整的構(gòu)造腳本大致流程如下import hashlib import time import uuid import base64 import json from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad SECRET_KEY sk_live_test_2024_x9k2 AES_KEY b32byteFixedKeyStringForAES AES_IV b16byteFixedIVString def aes_encrypt(plaintext): cipher AES.new(AES_KEY, AES.MODE_CBC, AES_IV) padded pad(plaintext.encode(utf-8), AES.block_size) encrypted cipher.encrypt(padded) return base64.b64encode(encrypted).decode(utf-8) def gen_sign(params): keys sorted(params.keys()) parts [f{k}{params[k]} for k in keys] raw .join(parts) key SECRET_KEY return hashlib.sha256(raw.encode(utf-8)).hexdigest() def build_request(): timestamp int(time.time()) nonce uuid.uuid4().hex business_data { user_id: u_10086, order_id: order_20240318_001, amount: 99.00, currency: CNY } data_enc aes_encrypt(json.dumps(business_data, separators(,, :))) params { app_id: test_app, timestamp: str(timestamp), nonce: nonce, data: data_enc } params[sign] gen_sign(params) return params if __name__ __main__: print(json.dumps(build_request(), indent2))腳本里的幾個關(guān)鍵點說明一下時間戳必須是當前Unix時間戳的字符串形式不能帶毫秒。nonce每次都要重新生成不能復(fù)用舊值。data的加密結(jié)果始終在變因為AES-CBC模式下相同的明文在固定的IV下雖然會得到相同的密文但你仍然要保證每次加密用的明文是你當前構(gòu)造的參數(shù)版本。簽名計算的輸入是params字典中除了sign字段之外的所有字段做字典序排序后的查詢字符串。腳本跑出來之后我直接把生成的請求提交到服務(wù)端返回的狀態(tài)碼是200響應(yīng)體里包含了正常的業(yè)務(wù)數(shù)據(jù)。這意味著整個逆向與重放過程完全成功——我手里現(xiàn)在握著一張能隨時訪問該接口的“合法通行證”。這個結(jié)果在實戰(zhàn)里就是最典型的業(yè)務(wù)漏洞場景掌握了簽名規(guī)則的人可以直接構(gòu)造任意參數(shù)提交給服務(wù)端服務(wù)端會認賬。如果接口本身沒有額外的風控策略比如IP限頻、設(shè)備指紋、用戶行為分析這個漏洞就會被無限放大。4. 常見問題與排查技巧實錄4.1 簽名長度正確但始終校驗失敗這是我第一次嘗試套公式時遇到的最大障礙。拿到64位十六進制字符串自然就想到SHA256但直接拼接參數(shù)老是驗不過。后來檢查源碼才發(fā)現(xiàn)密鑰參與拼接的格式是keyxxx不是常見的secret_keyxxx或者saltxxx。這類問題在真實環(huán)境中最難查因為你根本不知道鹽值的名字和位置。排查方法不要用猜的去找客戶端里生成簽名的實際代碼。如果代碼是混淆過的就先做格式化搜關(guān)鍵詞比如sha256、hmac、sign、md5、encrypt這類高頻詞。如果只有抓包數(shù)據(jù)沒有代碼就嘗試暴力枚舉拼接方式把參數(shù)順序、分隔符、鹽值名、鹽值位置全部作為變量去碰撞。4.2 時間戳不同步導致反復(fù)“過期”我在第一次構(gòu)造完新請求時本地系統(tǒng)時間沒有問題但提交后依然提示時間戳錯誤。仔細排查后發(fā)現(xiàn)本機時間差目標服務(wù)器5分鐘左右超過了服務(wù)端設(shè)置的容差窗口。這種情況下你除非能把本機時間校準否則無論簽名算得多正確都會失敗。經(jīng)驗是調(diào)研階段就先看一下目標返回的響應(yīng)頭里的Date字段或者任何時間相關(guān)字段以目標服務(wù)器的時間為基準來生成時間戳。不要默認“我的電腦時間就是準的”容器環(huán)境里差幾分鐘很正常。4.3 同一段明文加密結(jié)果不穩(wěn)定有朋友會問如果密鑰和IV都固定為什么每次生成的密文不一樣有可能的原因是服務(wù)端在密文中帶了隨機Salt比如CryptoJS的Salted__前綴格式。這類加密方式下即使明文和密鑰都相同生成的密文也不一樣因為每次加密都會生成一個新的隨機Salt。判斷的方法就是看密文開頭有沒有Salted__特征字節(jié)。如果你在逆向時忽略了Salt的存在直接用固定IV去解密結(jié)果必然失敗。正確做法是從密文中提取Salt按OpenSSL的推導方式計算出真實的密鑰和IV再解密。4.4 請求體解碼陷阱URL編碼與Base64變體在抓包和重放時我一直注意到請求體里data字段的Base64字符串里會出現(xiàn)和/字符這在標準的Base64編碼里正常。但有的時候后端接口期望URL安全的Base64變體把替換為-、把/替換為_如果直接拿標準Base64去提交服務(wù)端解析密文會出現(xiàn)填充錯誤報“wrong final block length”之類的異常。處理方式很簡單發(fā)送請求前把標準Base64轉(zhuǎn)換為URL安全的Base64或者請求時用表單/JSON體而不是URL參數(shù)傳遞。JSON請求體的話一般不需要額外轉(zhuǎn)換但如果是GET請求的參數(shù)拼接就必需要做URL編碼。4.5 客戶端腳本調(diào)試受阻有些環(huán)境里客戶端代碼做了重度混淆函數(shù)名、變量名全是單字母可讀性極差。我的建議是不要試圖讀懂所有邏輯而是只關(guān)注輸入輸出接口。運行腳本后在生成簽名的函數(shù)前后各打印一次關(guān)鍵變量的值用動態(tài)調(diào)試代替靜態(tài)分析。比對著正常請求和篡改后請求的輸出變化來定位關(guān)鍵函數(shù)比一個變量一個變量地去猜快得多。4.6 請求重放被限頻或者風控攔截這道題本身可能沒有風控但實戰(zhàn)接口十有八九會有。如果你發(fā)現(xiàn)自己構(gòu)造的請求明明簽名正確卻被直接拒絕或者返回驗證碼那大概率是觸發(fā)了其他維度的規(guī)則。常見的有IP頻率限制、設(shè)備標識校驗、請求方指紋校驗。這時候別硬懟頻率先把正常用戶的行為曲線復(fù)制下來把請求節(jié)奏降到接近真人的水平或者尋找可以復(fù)用設(shè)備標識的條件。5. 實操心得與避坑總結(jié)整套題解下來我最深的感覺是安全測試的價值不來自“發(fā)現(xiàn)了一個簽名是SHA256”而是來自“能完整地把一個合法請求從頭到尾構(gòu)造出來”。前者只是靜態(tài)知識后者才是在真實攻防里用得上的動態(tài)能力。有幾個習慣建議所有做這塊的人刻意培養(yǎng)每拿到一個請求樣本先拆字段不要急著爆破。把固定參數(shù)、動態(tài)參數(shù)、簽名參數(shù)、加密字段劃分清楚問題就解決了一半。所有推測都要用實驗驗證。懷疑時間戳過期就改時間懷疑密鑰寫在前端就搜索源碼懷疑算法是SHA256就寫腳本算一遍??障氩粫鼋Y(jié)果動手才會。構(gòu)造請求腳本盡量做到自動化。簽名、加密、時間戳、nonce、請求發(fā)送、結(jié)果校驗全部寫在同一個腳本里后續(xù)做批量測試或者參數(shù)變異時會省下大量重復(fù)勞動。這套“wsgsig secdd-challenge”做完之后我又順手把同類型的題目練了幾個發(fā)現(xiàn)整個流程基本是通用的。差別主要在加密算法的類型和密鑰的位置上但分析路徑始終一致。最后再分享一個小技巧不管題目多復(fù)雜先從抓包拿到一個“確定合法的請求”開始。這個樣本就是你所有分析的錨點。沒有它你會陷入“不知道正確答案長什么樣”的泥潭有了它后續(xù)每一步驗證都有明確參照。做接口安全分析錨點思維比任何技巧都重要。