zoukankan      html  css  js  c++  java
  • 玩转12306之系统登录

    【申明:本文所涉及的技术和分析的目的都是为了学习和交流,任何人使用文中所提的技术或成果做出的违法事情与我无关,大家购买火车票还是去12306官网上去购买。】

    从今天起,我开始分析12306网站的Http请求,以及编写一个客户端工具,废话不多说,这篇文章的重点是分析登录。

    常规的登录思路:账号+密码,稍微有点防范意识的:账号+密码+验证码,高级点的:账号+密码+验证码,其中密码加密。我们看看12306他是采用了哪些策略。

    首先进入12306的官网,尝试下登录,然后抓包,这里有个技巧,最好登录的时候用错误的密码或者验证码进行登录。

    如上图,发起了两个Post请求(一般提交的动作,跟踪post类的请求)

    我们先不管第一个请求是干嘛的(肯定是用的~),看看第二个请求,第二个请求显然提交登录的动作,继续抓包看看它到底提交了哪些参数。

     我们分析下参数的意义和来源:

    longinRand:969这个目前不得而知,refundLogin:N  这个写死就行了,refundFlag:Y 这个不得而知,loginUser.user_name:用户名,user.password:密码,randCode:验证码,

    NzYxNDgz:N2RlNzU1YWQ0ZTE5M2NiYg== 这个不得而知,动态参数。

    这个时候我们回头看看第一个请求,看他返回的是什么:

    {"loginRand":"969","randError":"Y"}

    至此,我们知道了longinRand,refundFlag是通过第一个请求得到的,soga...

    那么动态参数我们怎么取得呢?

    继续观察,https://dynamic.12306.cn/otsweb/loginAction.do?method=init 的源码(这个是初始化登陆页面,不要问我怎么知道的,观察,你懂的)

    发现里面有这么一段:

    <script src="/otsweb/dynamicJsAction.do?jsversion=5022&method=loginJstype="text/javascript"></script>

    这段脚本是干嘛的呢。。。果断下载下来,研究下,发现了奥妙:

    var inputObj=$('<input type="hidden" name="'+keyVlues[0]+'" value="'+encode32(bin216(Base32.encrypt(keyVlues[1],keyVlues[0])))+'" />');

    这个type为hidden的文本框,它的name为value度是动态取值的,注意到这句脚本里面gc()的方法 里面有一句var key='MzUyNzc0NQ==';

    这个显然就是我们的key了,那么value值了,通过阅读源码知道 ,原来这个方法是检测是否存在刷票插件,如果存在value=value+'0',否则value=value+'1';

    那么它是如何检测存在刷票插件的呢,接着看脚本

    var cssArr=['selectSeatType',' ev_light',' ev_light  ','fishTimeRangePicker','updatesFound','tipScript','refreshButton','fish_clock','refreshStudentButton'

    ,'btnMoreOptions','btnAutoLogin','fish_button','defaultSafeModeTime','ticket-navigation-item'];

    var idArr=['btnMoreOptions','refreshStudentButton','fishTimeRangePicker','helpertooltable','outerbox','updateInfo'

    ,'fish_clock','refreshStudentButton','btnAutoRefresh','btnAutoSubmit','btnRefreshPassenger'

    ,'autoLogin','bnAutoRefreshStu','orderCountCell','refreshStudentButton','enableAdvPanel','autoDelayInvoke','refreshButton','refreshTimesBar','chkAllSeat'];

    var keywordArr=[{
       key:".enter_right",values:["亲","抢票","助手"]
      }
      ,{
       key:".cx_form",values:["点发车","刷票"]
      }
      ,{
       key:"#gridbox",values:["只选","仅选","checkBox","checkbox"]
      }
      ,{
       key:".enter_w",values:["助手"]
      }
      ] ;

    原来,这个脚本作用有2个,一个是检测页面是否挂载了刷票的脚本工具,一个是动态生成一个密钥。看来12306的确被刷票工具搞得够惨,不得不应对了,因为这个脚本是动态生成的,所以12306可以定期生成这些关键词库,来防止,这个对于一般的刷票工具可以起到一定得作用,但是昨天我看了下猎豹的刷票的源码(仅举一例):

    <button class="normalButton" id="FriSep272013100801GMT08001" type="button" style="margin:0;97px;font-size:14px;vertical-align:middle;">♣ 刷  票</button>

    猎豹也够牛的,估计是上次12306更新了防刷脚本后,猎豹直接把自己的脚本上的控件ID都动态化了。。。。

    言归正传,刚才我们看到了动态key的产生,实际就是去请求https://dynamic.12306.cn/otsweb/loginAction.do?method=init,然后得到<script src="/otsweb/dynamicJsAction.do?jsversion=5022&method=loginJstype="text/javascript"></script>,进一步得到那个js的地址,然后从脚本中提取到var key=的值,这个就是动态key,那么动态value呢,刚才说过value值是检测刷票插件用的,咱直接无视,value为1111(因为它检测了4次)。

    继续看这句, value="'+encode32(bin216(Base32.encrypt(keyVlues[1],keyVlues[0])))+'",显然动态密码是经过加密的,传进的值就是动态key,动态value。怎么调用这个加密方法呢,我的做法是直接提取它的脚本加密函数为放到一个文件,然后用C#调用(详见:http://www.cnblogs.com/djhama/archive/2012/03/26/2418205.html

    提取到的密码脚本如下:

    function bin216(s){
            var i,l,o = "",n;
            s += "";
            b = "";
            for(i = 0,l = s.length;i < l;i ++ ){
                b = s.charCodeAt(i);
                n = b.toString(16);
                o += n.length < 2 ? "0" + n : n;
            }
            return o;
        };
        var Base32 = new function(){
            var delta = 0x9E3779B8;
            function longArrayToString(data,includeLength){
                var length = data.length;
                var n = (length - 1) << 2;
                if (includeLength){
                    var m = data[length - 1];
                    if((m < n - 3) || (m > n))return null;
                    n = m;
                }
                for(var i = 0;i < length;i ++ ){
                    data[i] = String.fromCharCode(data[i] & 0xff,data[i] >>> 8 & 0xff,data[i] >>> 16 & 0xff,data[i] >>> 24 & 0xff);
                }
                if (includeLength){
                    return data.join('').substring(0, n);
                }
                else{
                    return data.join('');
                }
            };
            function stringToLongArray(string, includeLength){
                var length = string.length;
                var result = [];
                for (var i = 0;i < length;i += 4){
                    result[i >> 2] = string.charCodeAt(i) |                string.charCodeAt(i + 1) << 8     |                string.charCodeAt(i + 2) << 16    |                string.charCodeAt(i + 3) << 24;
                }
                if (includeLength){
                    result[result.length] = length;
                }
                return result;
            };
            this.encrypt = function(string, key){
                if (string == ""){
                    return "";
                }
                var v = stringToLongArray(string, true);
                var k = stringToLongArray(key, false);
                if (k.length < 4){
                    k.length = 4;
                }
                var n = v.length - 1;
                var z = v[n], y = v[0];
                var mx, e, p, q = Math.floor(6 + 52 / (n + 1)), sum = 0;
                while (0 < q -- ){
                    sum = sum + delta & 0xffffffff;
                    e = sum >>> 2 & 3;
                    for (p = 0;p < n;p ++ ){
                        y = v[p + 1];
                        mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
                        z = v[p] = v[p] + mx & 0xffffffff;
                    }
                    y = v[0];
                    mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
                    z = v[n] = v[n] + mx & 0xffffffff;
                }
                return longArrayToString(v, false);
            };
        };
        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        function encode32(input){
            input = escape(input);
            var output = "";
            var chr1, chr2, chr3 = "";
            var enc1, enc2, enc3, enc4 = "";
            var i = 0;
            do{
                chr1 = input.charCodeAt(i ++ );
                chr2 = input.charCodeAt(i ++ );
                chr3 = input.charCodeAt(i ++ );
                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;
                if (isNaN(chr2)){
                    enc3 = enc4 = 64;
                }
                else if (isNaN(chr3)){
                    enc4 = 64;
                }
                output = output +             keyStr.charAt(enc1) +             keyStr.charAt(enc2) +             keyStr.charAt(enc3) +             keyStr.charAt(enc4);
                chr1 = chr2 = chr3 = "";
                enc1 = enc2 = enc3 = enc4 = "";
            }
            while (i < input.length);
            return output;
        };
    View Code

    OK,至此,我们需要的参数都搞定了,我们就可以模拟登陆了,最后捋一下登陆用到Http请求(按照顺序):

    1.加载验证码,用于获取图片和cookie

    https://dynamic.12306.cn/otsweb/passCodeNewAction.do?module=login&rand=sjrand(get)

    2.加载https://dynamic.12306.cn/otsweb/loginAction.do?method=init (get),用于获取动态生成key的请求地址,得到的地址是https://dynamic.12306.cn/otsweb/dynamicJsAction.do?jsversion=123123&method=loginJs

    3.请求https://dynamic.12306.cn/otsweb/dynamicJsAction.do?jsversion=123123&method=loginJs (get),得到动态key,然后调用加密js得到动态value

    4.请求https://dynamic.12306.cn/otsweb/loginAction.do?method=loginAysnSuggest(post),得到loginRand,refundfLag,

    5.构造参数,请求https://dynamic.12306.cn/otsweb/loginAction.do?method=login(post),然后解析返回的html。

    最后上一张我写的登录的图:

    敬请期待下一篇,玩转12306之购票查询。 

  • 相关阅读:
    linux 命令
    linux 命令
    linux 命令
    linux命令
    ubuntu 下安装ssh服务,并修改ssh端口
    爬虫基础
    Django之中间件
    Django之用户认证组件
    Django之cookie&session
    Django之forms组件
  • 原文地址:https://www.cnblogs.com/coding1016/p/3342077.html
Copyright © 2011-2022 走看看