序如诗

动态cookies不要方,js解密帮你忙(

最近用python搞爬虫玩儿,遇到了一个特别有趣的反爬网站。

规规矩矩走正门: 不挂任何代理,用浏览器正儿八经的打开,就能成功访问;

偷偷试探:挂上可用的代理ip,用浏览器装作正儿八经的打开,无法访问;

悄摸摸走侧门:用requests.get()打开官网,无法访问。

点开chrome万能的F12键,发现此网页有cookies:

哦~~~让我们斗胆猜测一下: 只有正确的cookies才能通过认证,查看网站中的内容 ?

虽然看着这么复杂的cookies,有点隐隐的担心它是动态随机的

但是因为怕麻烦,先把对方网站当弱智:说不定cookies过期时间很长呢~

先试试呗,又不亏x

(一顿操作猛如虎)

#! /usr/bin/env python3
# coding=utf-8

class Test_cookies(object):
    def __init__(self):
        #目标网址
        self.url = 'http://xxx.com'
        #请求头 自行补全 cookies从F12里扒拉
        self.headers = {
            'Host': "xxx",
            'Origin': "xxx",
            'User-Agent': "xxx",
            'Referer': "xxx",
            'Cookie': '__jsluid_h=xxx; tmas_cookie=xxx; JSESSIONID=xxx',
            'Connection': "keep-alive",
        }
    def get_page(self):
        response = requests.get(url=self.url, headers=self.headers, timeout=6) 
        #看一哈返回码
        print(response.status_code)
        print(response.text)


if __name__ == "__main__":
    test_cookies = Test_cookies()
    test_cookies.get_page()

“把别人当弱智的人,必将被别人当弱智。”

——by:鲁迅(鲁迅:我没说过!)

运行一下~会发现:

1.返回码是521

2.返回内容是一串很像js代码的字符串:

<script>var x="@Oct@String@@@setTimeout@@Array@@var@@@window@g@Path@fromCharCode@@@chars@href@@24@@while@substr@if@parseInt@@@a@0xEDB88320@createElement@@@__jsl_clearance@rOm9XFMtA3QKV7nYsPGT4lifyWwkq5vcjH2IdxUoCbhERLaz81DNB6@_p@return@JgSe0upZ@@D@@08@@x3XGR@pathname@@length@8@@@join@1@@@18@Gw@36@@onreadystatechange@kS@628@div@else@e@cookie@document@1500@attachEvent@challenge@DOMContentLoaded@@firstChild@split@@false@GMT@0@try@charCodeAt@replace@9@reverse@BcW@eval@@3@@d@Expires@@catch@f@function@captcha@search@@toLowerCase@@1571383481@19@@for@location@Fri@2@innerHTML@hantom@6@charAt@new@@@@ThpRmC@@match@@@0xFF@@BQuh@41@https@@addEventListener@toString@RegExp".replace(/@*$/,"").split("@"),y="a 9=3d(){6('3n.k=3n.1j+3n.3f.30(/[\\?|&]3e-2g/,\\'\\')',2e);2d.2c='18=3j.28|2o|'+(3d(){a 48=[3d(9){1b 9},3d(48){1b 48},(3d(){a 9=2d.15('29');9.3q='<13 k=\\'/\\'>35</13>';9=9.2j.k;a 48=9.49(/4g?:\\/\\//)[2o];9=9.p(48.1l).3h();1b 3d(48){3m(a 35=2o;35<48.1l;35++){48[35]=9.42(48[35])};1b 48.1p('')}})()],35=[(((-~[]<<-~[])<<(+!-{}))+[]+[[]][2o]),(1m+[]),[([3p]+~~{}>>3p)],(-~{}+[]+[[]][2o])+[36],(-~{}+[]+[[]][2o]),[36],(-~{}+[]+[[]][2o])+(~~{}+[[]][2o]),(~~{}+[[]][2o]),(31+[]+[]),[41],(-~{}+[]+[[]][2o])+((-~[]<<-~[])+[]+[[]][2o]),(-~-~!/!/+(-~[]+[~~''])/[-~~~!!d['1a'+'40']-~~~!!d['1a'+'40']]+[]+[]),((-~[]<<-~[])+[]+[[]][2o]),(-~{}+[]+[[]][2o])+(-~{}+[]+[[]][2o])];3m(a 9=2o;9<35.1l;9++){35[9]=48[[2o,1q,2o,1q,2o,1q,2o,1q,2o,1q,2o,1q,2o,1q][9]](['4e%',(-~{}+[]+[[]][2o])+[41],[36],'47%',[!(+!/!/)+[]+[[]][2o]][2o].42(-~{}),[36],'33','23%','27',((-~[]<<-~[])+[]+[[]][2o]),((-~[]<<-~[])+[]+[[]][2o]),'1e',(1m+[]),'1i'][35[9]])};1b 35.1p('')})()+';39=3o, 22-2-3k 1g:m:4f 2n;f=/;'};q((3d(){2p{1b !!d.4i;}3b(2b){1b 2m;}})()){2d.4i('2h',9,2m)}2a{2d.2f('26',9)}",f=function(x,y){var a=0,b=0,c=0;x=x.split("");y=y||99;while((a=x.shift())&&(b=a.charCodeAt(0)-77.5))c=(Math.abs(b)<13?(b+48.5):parseInt(a,36))+y*c;return c},z=f(y.match(/\w/g).sort(function(x,y){return f(x)-f(y)}).pop());while(z++)try{eval(y.replace(/\b\w+\b/g, function(y){return x[f(y,z)-1]||("_"+y)}));break}catch(_){}</script> @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

很明显,被网站拦截了_(:з」∠)_

以后我抓包一定更加仔细,不再犯这种弱智错误了(说是这样说,下次还敢)

再用正经方法,打开浏览器仔细看看网页跳转全流程,加上用requests观察规律,发现有几个可疑点:

1.刚打开网页,cookies只有3个;但跳转二级页面后cookies增加了一个

2.521返回的就是那一长串看起来是js的字符串。不传cookies/开启代理ip/用postman更换 User-Agent 访问后,每次访问返回的字符串都不同

3.很多代理ip可以上其他网站,但是打不开目标网站。抓包里根本没有跳转过521,直接被403拒绝

让我们大胆猜测:

1.这个js的代码,就是用来增加隐藏的幕后黑手cookies的

2.隐藏的cookies就是运行这串js代码来生成的

3.这串js代码和ip, User-Agent 有关

4.网站可能有封锁一些代理ip

反正是运行随机js获取到的cookies,现在我们面前有两个选择:

方案1.开启chrome无头浏览器+selenium,获取cookies

优点:兵来将挡,水来土掩。来啥js自动运行啥js,只要配好了无头+自动化环境,就不用带脑子了

缺点:cookies的过期时间是由网页控制的,都上了js加密的网站,cookies一定会卡的很严

方案2.破解js加密

优点:正面刚。来啊,这才是猛男该做的!

缺点:过前方黑漆漆的独木桥。不知道js容不容易破解,如果遇到调用浏览器window函数啥的,因为我们没有开启浏览器,所以会特别吃力

像我这么猛男的人,当然选择2了!

(不行咱还可以认怂,走方案1嘛)

包含的js代码字符串太乱了,去掉后面看起来就像凑数的@@@和空格,我们格式化一下:

<script>
var x="@Oct@String@@@setTimeout@@Array@@var@@@window@g@Path@fromCharCode@@@chars@href@@24@@while@substr@if@parseInt@@@a@0xEDB88320@createElement@@@__jsl_clearance@rOm9XFMtA3QKV7nYsPGT4lifyWwkq5vcjH2IdxUoCbhERLaz81DNB6@_p@return@JgSe0upZ@@D@@08@@x3XGR@pathname@@length@8@@@join@1@@@18@Gw@36@@onreadystatechange@kS@628@div@else@e@cookie@document@1500@attachEvent@challenge@DOMContentLoaded@@firstChild@split@@false@GMT@0@try@charCodeAt@replace@9@reverse@BcW@eval@@3@@d@Expires@@catch@f@function@captcha@search@@toLowerCase@@1571383481@19@@for@location@Fri@2@innerHTML@hantom@6@charAt@new@@@@ThpRmC@@match@@@0xFF@@BQuh@41@https@@addEventListener@toString@RegExp".replace(/@*$/,"").split("@"),

y="a 9=3d(){6('3n.k=3n.1j+3n.3f.30(/[\\?|&]3e-2g/,\\'\\')',2e);2d.2c='18=3j.28|2o|'+(3d(){a 48=[3d(9){1b 9},3d(48){1b 48},(3d(){a 9=2d.15('29');9.3q='<13 k=\\'/\\'>35</13>';9=9.2j.k;a 48=9.49(/4g?:\\/\\//)[2o];9=9.p(48.1l).3h();1b 3d(48){3m(a 35=2o;35<48.1l;35++){48[35]=9.42(48[35])};1b 48.1p('')}})()],35=[(((-~[]<<-~[])<<(+!-{}))+[]+[[]][2o]),(1m+[]),[([3p]+~~{}>>3p)],(-~{}+[]+[[]][2o])+[36],(-~{}+[]+[[]][2o]),[36],(-~{}+[]+[[]][2o])+(~~{}+[[]][2o]),(~~{}+[[]][2o]),(31+[]+[]),[41],(-~{}+[]+[[]][2o])+((-~[]<<-~[])+[]+[[]][2o]),(-~-~!/!/+(-~[]+[~~''])/[-~~~!!d['1a'+'40']-~~~!!d['1a'+'40']]+[]+[]),((-~[]<<-~[])+[]+[[]][2o]),(-~{}+[]+[[]][2o])+(-~{}+[]+[[]][2o])];3m(a 9=2o;9<35.1l;9++){35[9]=48[[2o,1q,2o,1q,2o,1q,2o,1q,2o,1q,2o,1q,2o,1q][9]](['4e%',(-~{}+[]+[[]][2o])+[41],[36],'47%',[!(+!/!/)+[]+[[]][2o]][2o].42(-~{}),[36],'33','23%','27',((-~[]<<-~[])+[]+[[]][2o]),((-~[]<<-~[])+[]+[[]][2o]),'1e',(1m+[]),'1i'][35[9]])};1b 35.1p('')})()+';39=3o, 22-2-3k 1g:m:4f 2n;f=/;'};q((3d(){2p{1b !!d.4i;}3b(2b){1b 2m;}})()){2d.4i('2h',9,2m)}2a{2d.2f('26',9)}",

f=function(x,y){var a=0,b=0,c=0;x=x.split("");y=y||99;while((a=x.shift())&&(b=a.charCodeAt(0)-77.5))c=(Math.abs(b)<13?(b+48.5):parseInt(a,36))+y*c;return c},

z=f(y.match(/\w/g).sort(function(x,y){return f(x)-f(y)}).pop());while(z++)try{eval(y.replace(/\b\w+\b/g, function(y){return x[f(y,z)-1]||("_"+y)}));break}catch(_){}
</script>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

哇~真的清晰了很多呢~如果说格式化以前是100%看不懂,现在就是50%看不懂了呢~

但是至少知道了:原来声明了4个变量啊~

只要我们把这串代码看懂,不就可以看到幕后终极boss的cookie了吗~

接下来,向大噶推荐一个python的第三方库:execjs

它是可以运行简单的js代码的。(注意:是简单)

ubuntu中用pip安装很简单:

使用也很简单:

execjs.eval("字符串")类似于python的eval()函数。用来解析js字符串
#调用js中的函数
execjs.compile("全部js字符串").call("全部js字符串中的函数名", 函数传参1, 函数传参2...)

可以自己配置execjs的解析环境:

os.environ["EXECJS_RUNTIME"] = "Node"
这里的环境就变成了Node.前提是已经装了Node

根据我和这串js代码斗智斗勇的过程中,发现不是所有的js都能被execjs解析成功。如:

1.shift()函数

2.所有的window、 document 函数。因为我们没有这两个对象

...

为什么我会知道呢~因为这个js代码里很喜欢调用window和document~(说多了都是泪)

先不方,看了看,发现它用document新建元素啥的,和我们要的cookie无关!

window也只是为了混淆,搞清楚函数功能后可以直接用正则替代!

y变量里其实是加密后的字符串,钥匙是f,对应明文是x变量

一顿骚操作执行js后,真实的y为:

var _15=function(){setTimeout('location.href=location.pathname+location.search.replace(/[\?|&]captcha-challenge/,\'\')',1500);document.cookie='__jsl_clearance=1571101598.377|0|'+(function(){var _2E=[function(_15){return _15},function(_2E){return _2E},(function(){var _15=document.createElement('div');_15.innerHTML='<a href=\'/\'>_p</a>';_15=_15.firstChild.href;var _2E=_15.match(/https?:\/\//)[0];_15=_15.substr(_2E.length).toLowerCase();return function(_2E){for(var _p=0;_p<_2E.length;_p++){_2E[_p]=_15.charAt(_2E[_p])};return _2E.join('')}})(),function(_15){for(var _2E=0;_2E<_15.length;_2E++){_15[_2E]=parseInt(_15[_2E]).toString(36)};return _15.join('')}],_15=['LBc',[-~!{}-~!{}-~-~{}+((+!+[])<<(+!+[]))+(-~-~{}^(+!+[]))],'N',[[-~-~{}]+[-~-~{}],[-~-~{}]+[~~!{}],(-~[-~-~{}]+[])+(-~!{}-~[-~-~{}]+[]+[])],'rF',[[]/!![][[]]+[[]][0]][0].charAt(2),[(-~~~!{}+[[]][0])+[-~-~{}]],'W',[(-~~~!{}+[[]][0])+[-~~~!{}+((+!+[])<<(+!+[]))+((+!+[])<<((+!+[])<<(+!+[])))]],'d',[(-~~~!{}+[[]][0])+(-~~~!{}+[[]][0])],'XJqSJ6',[[-~-~{}]+(-~~~!{}+[[]][0])],'a3fk%3D'];for(var _p=0;_p<_15.length;_p++){_15[_p]=_2E[[1,0,1,3,1,0,2,1,3,1,2,1,3,1][_p]](_15[_p])};return _15.join('')})()+';Expires=Tue, 15-Oct-19 02:06:38 GMT;Path=/;'};if((function(){try{return !!window.addEventListener;}catch(e){return false;}})()){document.addEventListener('DOMContentLoaded',_15,false)}else{document.attachEvent('onreadystatechange',_15)}

800年了,终于看到了"document.cookie" 这个字段,胜利在望了!

隐藏的cookie就是__jsl_clearance!

把这个js执行后就可以拿到cookie了!

胜利撒花!

(ps:execjs解析js比较慢,大概40s左右才能拿取到解密后的cookie,建议选择一个稳定的ip实行)


后续:过了一星期后,发现网站的cookie变了,不再有__jsl_clearance这个cookie

拿数据的post请求参数中也新增了一个变量,这个变量的值是另一个接口的response

post请求传参也变了....

总的来说,还是比js解密要容易多了...

对这类反爬严重的网站,只能长期奋斗了!


后后续:最终的我,因为网站反爬老变,还是向无头浏览器屈服了OTZ

不带脑子真好啊~

— 于 共写了8067个字
— 文内使用到的标签: