玩转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=loginJs"  type="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;width: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=loginJs"  type="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之购票查询。 

转载于:https://www.cnblogs.com/coding1016/p/3342077.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/408457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react学习(10)----react数组定义 从0开始 直接加个0下标空

{title: 状态,dataIndex: status,render: (text, row) > {let arr [, 未开始, 进行中, 已结束, 已作废];return <span>{arr[text]}</span>;},},

Nginx快速搭建和基本使用

2019年第 83 篇文章&#xff0c;总第 107 篇文章最近在工作中项目需要上线&#xff0c;所以也了解到关于一些部署上线的知识内容&#xff0c;Nginx 就是其中一个知识点&#xff0c;主要是可以用它来进行负载均衡&#xff0c;本文的目录如下&#xff1a;简介安装配置基本使用简介…

对于mysql的用户权限管理

转载链接&#xff1a;http://www.cnblogs.com/ymy124/archive/2012/05/23/2514196.html 1.新建用户 //登录MYSQL>mysql -u root -p>密码//创建用户mysql> insert into mysql.user(Host,User,Password) values(‘localhost’,jeecn’,password(‘jeecn’));//刷新系统权…

第二期周总结

第二期的周总结&#xff0c;这次学习的内容可能没有上次那么广泛&#xff0c;主要是因为这周我负责的模块需要测试并进行上线&#xff0c;所以主要学习了解的就是工程开发方面的内容&#xff0c;准确说是部署上线的内容&#xff0c;所以本周主要简单总结这次上线过程的一些内容…

react学习(12)-moment插件设置日期格式

<p>{moment(boothDetails.startTime).format(YYYY-MM-DD)}到{moment(boothDetails.endTime).format(YYYY-MM-DD)}</p>

AI知识点(1)--激活函数

2019年第 84 篇文章&#xff0c;总第 108 篇文章本文大约 5000 字&#xff0c;阅读大约需要 15 分钟AI知识点&#xff08;AI Knowledge&#xff09;系列第一篇文章--激活函数。本文主要的目录如下&#xff1a;激活函数的定义为什么需要激活函数常见的激活函数1. 激活函数的定义…

oracle分区

oracle 分区技术&#xff1a;使用分区技术&#xff0c;Oracle允许把一个大表分成几个部分&#xff0c;每部分叫一个分区&#xff0c;然后把每个部分放在不同的物理磁盘&#xff0c;以提高整个数据库的性能。分区技术的优点&#xff1a;1.分区技术使数据库的可管理性变得更加容易…

react学习(13)-moment中 isRangePicker 控制类型

<Col span{8} key{index}><Form.Item label{item.label} {...formItemLayout}>{getFieldDecorator(${item.paramsName}, {})(item.isRangePicker ? (<RangePickershowTime{item.showTime ? item.showTime : false}style{{ width: 100% }}allowClear/>) : (…

Linux 定时执行shell 脚本

2019年第 85 篇文章&#xff0c;总第 109 篇文章本文大约2000字&#xff0c;阅读大约需要6分钟crontab 可以在指定的时间执行一个shell脚本以及执行一系列 Linux 命令。定时执行shell 脚本简单给出执行 shell 脚本的步骤。首先是编写一个测试脚本--test.sh# 创建脚本 $ vim tes…

react学习(14)-getTime是对时间进行处理的方法

{name: data?.name,startTimeLong: new Date(data?.code[0]).getTime(),endTimeLong: new Date(data?.code[1]).getTime(),},() > {this.getFrameList();}

同余定理

http://www.cnblogs.com/zhixingqiezhixing/archive/2012/04/03/2430676.html http://blog.sina.com.cn/s/blog_6e223f1d0101bkry.html 转载于:https://www.cnblogs.com/thefirstfeeling/p/4410970.html

简单总结 2019 展望 2020

2019 总结整体回顾一下今年&#xff0c;一个完整的经济独立的一年&#xff0c;也是工作满一年&#xff0c;改变很多&#xff0c;虽然有进步&#xff0c;但还不够明显&#xff0c;依然存在的三分钟热度、拖延、执行力低下的问题。工作这一年做的还是同一个项目&#xff0c;不过具…

react学习(15)-getTime selectedRowKeys是this.props取值的

const rowSelection {selectedRowKeys,onChange: this.onSelectChange,};

RS(1)--10分钟了解什么是推荐系统

总第 110 篇文章&#xff0c;本文大约 3200 字&#xff0c;阅读大约需要 10 分钟2020 年第一篇技术文章&#xff0c;以一个新的系列开始--推荐系统&#xff08;Recommend System&#xff09;&#xff0c;第一篇文章会简单介绍推荐系统的定义和应用&#xff0c;目录如下&#xf…

当搭配遇上个性化推荐

总第 111 篇文章&#xff0c;本文大约 3000 字&#xff0c;阅读大约需要 10 分钟今天介绍的是一篇个性化搭配推荐的论文&#xff0c;是 2017 年时候的论文&#xff0c;这也是比较早的开始结合搭配和个性化推荐的一个工作&#xff0c;基于度量学习和排序学习的方法。论文题目&am…

清除浮动造成的影响的解决方案总结

1、将设置float的元素的父元素也设置float。 缺点&#xff1a;很有可能不符合情况要求 2、设置父元素的position为absolute&#xff0c;前提是父元素的父元素并没有设置position&#xff1a;relative。 缺点&#xff1a;很有可能不符合情况要求 3、设置父元素的overflow为hidde…

2020年周记(1/50)

总第 112 篇文章&#xff0c;本文大约 1200 字&#xff0c;阅读大约需要 3 分钟正如标题所言&#xff0c;希望 2020 年能写满 50 篇周记吧&#xff0c;刚好前两周没有发&#xff0c;所以希望接下来每周完成一篇。周记的内容主要是这几方面的内容&#xff1a;工作学习阅读&…

react学习(16)---getFieldDecorator赋值

<Row gutter{12}><Col span{12}><Form.Item label"名称">{getFieldDecorator(name, {rules: [{ required: true, message: 活动名称不能为空 }],})(<Input placeholder"请输入" />)}</Form.Item></Col></Row>

python版代码整洁之道

总第 113 篇文章&#xff0c;本文大约 8000 字&#xff0c;阅读大约需要 20 分钟原文&#xff1a;https://github.com/zedr/clean-code-pythonpython 版的代码整洁之道。目录如下所示&#xff1a;介绍变量函数1. 介绍软件工程的原则&#xff0c;来自 Robert C. Martins 的书--《…