js cookie反爬實戰


理論基礎

取自《Python-3反爬蟲原理與繞過實戰》
Cookie不僅可以用於Web服務器的用戶身份信息存儲或狀態保持,還能夠用於反爬蟲。大部分的爬蟲程序在默認情況下只請求HTML文本資源,這意味着它們並不會主動完成瀏覽器保存Cookie的操作。Cookie反爬蟲指的是服務器端通過校驗請求頭中的Cookie值來區分正常用戶和爬蟲程序的手段,這種手段被廣泛應用在Web應用中,例如瀏覽器會自動檢查響應頭中是否存在Set-Cookie頭域,如果存在,則將值保存在本地,而且往后的每次請求都會自動攜帶對應的Cookie值,這時候只要服務器端對請求頭中的Cookie值進行校驗即可。服務器會校驗每個請求頭中的Cookie值是否符合規則,如果通過校驗,則返回正常資源,否則將請求重定向到首頁,同時在響應頭中添加Set-Cookie頭域和Cookie值。

實戰

觀察

打開開發者工具,切換頁面,看一看我們要爬取的目標的接口url是哪個

發現目標就是一串類似uuid的url,再看看html,那么其實這一串uuid組成的url我們是可以通過a標簽獲得的,現在只要爬取我們的目標的具體信息即可

看一下我們的具體信息在html中是何種表現形式

可以看到也是一個a標簽的形式,那么我們的思路就明確了

隨便找一個uuid的url=>
通過詳細信息的a標簽中的鏈接爬取所有的詳細信息=>
通過下一頁的a標簽中的鏈接訪問下一頁的url=>
一直循環直到頁空的盡頭

那我們寫一個簡單的爬蟲看看能不能爬取到,直接用網站

import requests

cookies = {
    'Hm_lvt_9511d505b6dfa0c133ef4f9b744a16da': '1631673117',
    'ASP.NET_SessionId': 'xel3j5xxd5fxgu5rgv0cf2ms',
    'spvrscode': 'abdc551c0bd7f81cca4e2804c23afe646e1a1904a5570f1e626ce42731a8b2bb7e2ac5430a0b4c2671adf2973523fe3be72a87e6e56c76657e1ac381a254570e7ac433db747372123549b582c4dfa98f60816aca302433f60fddfbff563c19556c1cb013f26eadbd5d81d8ffc0a22fae8275c1fd42b386c2ef1d085048ae3a9a544793a7c2307dd2',
    'Hm_lpvt_9511d505b6dfa0c133ef4f9b744a16da': '1631685108',
}

headers = {
    'Connection': 'keep-alive',
    'sec-ch-ua': '"Microsoft Edge";v="93", " Not;A Brand";v="99", "Chromium";v="93"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-User': '?1',
    'Sec-Fetch-Dest': 'document',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
}

response = requests.get('https://www.***.***/15022E858978-A7C0-4D99-A602-967A31FB4828.html', headers=headers, cookies=cookies)
print(response.text)


可惡世上果然沒有簡單的事情,我們遇到了高手,可以和學員說這個是個高手耶穌來了也救不了。。。。。。那是不可能的,繼承自肉絲老師服務第一的傳統,有困難就要解決,解決不了也要硬解決,還是拿起我的水壺邊喝水邊分析吧。拿出我多年未見的老朋友burpsuit(上次一別以是一年),一點一點的試一下,發送到repeater,一個一個的刪除參數,最后終於定位到了是cookie中的spvrscode=,當它為空的時候會返回一串js代碼,當cookie過期的時候他就會返回非授權訪問,那么現在就用之前的cookie通殺腳本來進行定位cookie是如何生成的。

var cookie = document.cookie;
document = Object.defineProperty(document, 'cookie', {
  get: function () {
    console.log('getter: ' + cookie);
    return cookie;
  },
  set: function (value) {
    console.log('setter: ' + value);
    cookie = value
  }
});

先把數據和cookie都清一清,然后注意這里他會網頁重定向刷新一次網頁,這時候如果我們在script上下斷點執行一次hook直接放開的話,重定向就會把我們的hook給刷新掉,所以可以使用油猴腳本hook或者在每個斷點都運行一下hook腳本

最終定位到了這里

就是一個查看一下ck的值,看看是不是我們想要的結果

就是我們想要的cookie的值,那么這里就可以開始逆向工作了,一步一步的回溯ck是怎樣生成的

 ck=_0x3cc240(0x90) + b + _0x3cc240(0x8b) + exp[_0x3cc240(0x95)]() + ';'
_0x3cc240(0x90)='spvrscode='
b='e73fbff4ed0cd6bdd7a2b41a2b2c915ce7b0b047552752268c1ea11adfc9b5422c33f2ec7cfdc9fe0b7df5ca707503f80b0039c93e8636c6ac1063c135494a1a6254d35b623e2f4803a67ac44ec8c7e99f517d25fbec1f7dfbfb569004d7eef408ad6e675c4562172112e4e1da5f359d25e07e80915b71794669e0f88c6f11b39a0e5d34695d5bc9'//目標
...//剩下作用不大

接着追b

b = escape(encryptvrscode)
encryptvrscode='e73fbff4ed0cd6bdd7a2b41a2b2c915ce7b0b047552752268c1ea11adfc9b5422c33f2ec7cfdc9fe0b7df5ca707503f80b0039c93e8636c6ac1063c135494a1a6254d35b623e2f4803a67ac44ec8c7e99f517d25fbec1f7dfbfb569004d7eef408ad6e675c4562172112e4e1da5f359d25e07e80915b71794669e0f88c6f11b39a0e5d34695d5bc9'//目標
encryptvrscode = encrypted[_0x3cc240(0x97)][_0x3cc240(0x8f)]()
_0x3cc240(0x97)='ciphertext'
_0x3cc240(0x8f)='toString'

那么就繼續追蹤encrypted,探索一下子是個牛馬對象

var keyHex = CryptoJS['enc'][_0x3cc240(0xa3)][_0x3cc240(0xa4)](a)
      , encrypted = CryptoJS[_0x3cc240(0xa2)][_0x3cc240(0x8a)](b, keyHex, {
        'mode': CryptoJS[_0x3cc240(0xaf)]['ECB'],
        'padding': CryptoJS[_0x3cc240(0xa9)][_0x3cc240(0x99)]
    })

CryptoJS....,眼前一亮,藍師傅說過的加密庫,翻譯一下即可

_0x3cc240(0xa3)='Utf8'
_0x3cc240(0xa4)='parse'
a='eb74960d'
_0x3cc240(0xa2)=`DES`
_0x3cc240(0x8a)='encrypt'
_0x3cc240(0xa9)=`pad`
_0x3cc240(0x99)=`Pkcs7`
b='E04A051E2E4370CE3F2AB90D7ECF6CFAC225C8B8FC6076977E8546DC17C7F890D3D442529EEE9941C3BDE3766931B7C846F43BBB36E02E3ED90B87B40A96AEDF'//此b非彼b所以下面的結果和前面的不一樣,下面用新的b開始

翻譯一下

var keyHex = CryptoJS['enc']['Utf8']['parse']('eb74960d')
      , encrypted = CryptoJS[`DES`]['encrypt'](b, keyHex, {
        'mode': CryptoJS[`mode`]['ECB'],
        'padding': CryptoJS[`pad`][`Pkcs7`]
    })

這時候可以去看一下百度上CryptoJS的使用案例,我們就知道它的加密流程了,官方使用流程大概如下

var CryptoJS = require("crypto-js");

// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString();

// Decrypt
var bytes  = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var originalText = bytes.toString(CryptoJS.enc.Utf8);

console.log(originalText); // 'my message'

其實這就是一個DES加密的ECB模式,那么我們可以找一個網站試一下(密鑰又換了又刷新了一下)


可以看到一模一樣,那么我們就知道了這是個標准算法,python能夠簡單的實現,那么現在還有一個問題就是key和b是哪來的,向上追溯可以發現是js中自帶的

  var a = '7a957fbd';
var b = '06D9057FAC69E1AE39B3A37E03AFDCBD4ADF15025C574F066CC2955184438E628FC2C4B99FB54308949051450B883FF2AB5155516482D79AB0B22FF8553ACD7C';
  

over,可以開始寫程序了

第一次訪問隨便找一個uuid的url得到js=>
第二次攜帶cookie訪問url得到我們要的html數據=>
通過詳細信息的a標簽中的鏈接爬取所有的詳細信息=>
通過下一頁的a標簽中的鏈接訪問下一頁的url=>
一直循環直到頁空的盡頭

這里我選擇了,直接調用js代碼,也可以寫正則匹配拿到message和key,並且補環境也用了之前的代碼,跑一遍js還是缺環境了,安裝一個CryptoJS

npm install crypto-js

然后導入,發現結果

var CryptoJS = require("crypto-js");
......
console.log(ck)

那么現在就可以寫我們的腳本進行爬取了,成功得到cookie的值,期間需要加入一個getcookie函數,和使用execjs這個之前都講過這里不再贅述了,落地加載js(其實不落地也行)

response = requests.get('https://****.***.***/15022E858978-A7C0-4D99-A602-967A31FB4828.html', headers=headers, cookies=cookies)
pattern = re.compile("<script>(.*)</script>",re.S)
jscode = pattern.findall(response.text)[0]
with open("./MyProxy.js", "r") as f:
    envcode = f.read()

getcookie="function getcookie(){return document.cookie;}"
allcode = envcode + jscode+"\n"+getcookie;
with open("./allcode.js", "w") as f:
    f.write(allcode)
ctx = execjs.compile(allcode)
spvrscode = ctx.call("getcookie")
print(spvrscode)


但是要注意,這個網址是spvrscode與sessionid一一對應的,所以要定義類來進行統一會話,最終代碼如下

class spider:
    def __init__(self):
        self.session = requests.session()

    def getdata(self, url):
        headers = {
            'Connection': 'keep-alive',
            'Pragma': 'no-cache',
            'Cache-Control': 'no-cache',
            'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
            'sec-ch-ua-mobile': '?0',
            'Upgrade-Insecure-Requests': '1',
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
            'Sec-Fetch-Site': 'same-origin',
            'Sec-Fetch-Mode': 'navigate',
            'Sec-Fetch-User': '?1',
            'Sec-Fetch-Dest': 'document',
            'Accept-Language': 'zh-CN,zh;q=0.9',
        }

        response = self.session.get(url, headers=headers)
        html = response.text
        if "******" not in response.text:
            pattern = re.compile("<script>(.*)</script>",re.S)
            jscode = pattern.findall(response.text)[0]
            with open("./MyProxy.js", "r") as f:
                envcode = f.read()

            getcookie = "function getcookie(){return b;}"
            allcode = envcode + jscode + "\n" + getcookie;
            with open("./allcode.js", "w") as f:
                f.write(allcode)
            ctx = execjs.compile(allcode)
            spvrscode = ctx.call("getcookie")
            requests.utils.add_dict_to_cookiejar(self.session.cookies, {"spvrscode": spvrscode})
            response = self.session.get('***********', headers=headers)
            html = response.text
            print(self.session.cookies.values())


if __name__ == '__main__':
    s=spider();
    s.getdata("https://***********")


得到了html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM