[ 生活需要仪式感 ]

0%

PHP模拟登陆广工教务系统

原理
先取COOKIE和验证码图片,然后PHP模拟用户进行POST请求登陆。

抓包分析

我是用Windows系统下的Fiddler抓包的,当然你也可以用chrome自带的开发者工具来抓,只要抓到我们登陆时POST请求就好.

Fiddler

这个表单就是我们用户登录上去时POST请求的表单数据,还有一个暗藏的__VIEWSTATE其实是隐藏在登陆页的登录表单中,

然后把cookie附在header里了。

Fiddler2

ASP.NET_SessionId=pybgm0i40egzq12db3tteo55

所以PHP只要模拟提交 组装好的表单 & cookies ,就能模拟用户登陆。


前期准备

我把用户登录页(GET方法),到模拟登陆后页面的呈现(POST方法)都写在同一个php文件里,所以我通过$_SERVER['REQUEST_METHOD']来判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   header('Content-Type: text/html; charset=gb2312');
$url='http://jwgldx.gdut.edu.cn/default2.aspx';
$verify_url='http://jwgldx.gdut.edu.cn/CheckCode.aspx';

if($_SERVER['REQUEST_METHOD']=='GET'){

code...

}elseif($_SERVER['REQUEST_METHOD']=='POST') {

code...

}else{

code...

}

用户登录页

找到cookie & 隐藏信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

/*
* 找出COOKIE&默认信息
*/

$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl,CURLOPT_HEADER,1);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
$html_file=curl_exec($curl);
curl_close($curl);

//查找cookie
preg_match('/Set-Cookie:(.*);/iU',$html_file,$cookies);
$cookie=$cookies[1];

//查找__VIEWSTATE
$pattern='/<input type="hidden" name="__VIEWSTATE" value="(.*?)" /';
preg_match_all($pattern,$html_file,$matches);
$__VIEWSTATE = $matches[1][0];

/*
* 找出验证码
*/
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$verify_url);
curl_setopt($curl,CURLOPT_HEADER,0);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
curl_setopt($curl, CURLOPT_COOKIE, $cookie);
$verify_image=curl_exec($curl);
curl_close($curl);
//按时间戳给验证码图片命名,避免多用户验证码冲突
$pic_name="./VerifyCode/Verify".time().".gif";
$fp=fopen($pic_name,"w+");
fwrite($fp,$verify_image);
fclose($fp);

/*
* 显示前段页面给用户操作
*/
echo "<div><img src='{$pic_name}' /></div>";
echo "<div>
<form action='index.php' method='post'>
<input type='hidden' name='__VIEWSTATE' value='{$__VIEWSTATE}'/>
<input type='hidden' name='cookies' value='{$cookie}'/>
<p>Verify Code:<input type='text' name='UserVerifyCode' /></p>
<p>StudentID:<input type='text' name='StudentId' /></p>
<p>StudentPass:<input type='password' name='StudentPass' /></p>
<input type='submit' value='submit' />
</form>
</div>";

模拟登陆页

取用户输入数据 & 组装POST数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
* 取回用户输入数据,还未做过滤处理
*/
$__VIEWSTATE=$_REQUEST['__VIEWSTATE'];
$StudentId=$_REQUEST['StudentId'];
$StudentPass=$_REQUEST['StudentPass'];
$cookies=$_REQUEST['cookies'];
$UserVerifyCode=$_REQUEST['UserVerifyCode'];

/*
* 组装POST数据
*/
$post_data = array(
"__VIEWSTATE" => $__VIEWSTATE,
"txtUserName" => $StudentId,
"TextBox2" => $StudentPass,
"txtSecretCode" => $UserVerifyCode,
"RadioButtonList1" => "%D1%A7%C9%FA",
"Button1" => "",
"lbLanguage" => "",
"hidPdrs" => "",
"hidsc" => ""
);

模拟登陆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*
* 模拟登陆
*/

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_COOKIE, $cookies);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
curl_exec($curl);
curl_close($curl);

//学生个人主页
$main_url="http://jwgldx.gdut.edu.cn/xs_main.aspx?xh=".$post_data['txtUserName'];

//配置header信息
$headers =array();
$headers[]='Connection: keep-alive';
$headers[]='Upgrade-Insecure-Requests: 1';
$headers[]='User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36';
$headers[]='Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
$headers[]='DNT: 1';
$headers[]='Referer: http://jwgldx.gdut.edu.cn/xs_main.aspx?xh='.$post_data['txtUserName'];
$headers[]='Accept-Encoding: gzip, deflate, sdch';
$headers[]='Accept-Language: zh-CN,zh;q=0.8,en;q=0.6';

//正方系统登陆后要跳转,所以要再请求一次
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $main_url);
curl_setopt($curl, CURLOPT_HTTPHEADER,$headers);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_COOKIE, $cookies);
$da=curl_exec($curl);
curl_close($curl);
print_r($da);

结果显示

看到熟悉的字眼,说明已经正常登录了。那么接下来的[个人课表]、[成绩查询]的原理也是相近的。


遇到的问题

  1. 获取验证码
    需要第一次用curl去请求教务系统,取得cookie,并把cookie保存下来,再用这个cookie去请求验证码图片,就能得到正确的验证码。

  2. 验证码有效性
    我发现只要是同一个cookie,无论你是第几次请求验证码页面,得到的任意验证码拿去post都能正常登录。

  3. 多用户登录
    我命名验证码图片时,都在后面加了时间戳保持各自独立性,确保多用户登录时不会共用一个验证码出现错误。

  4. 用户主页信息获取
    因为正方系统正常登录后,会跳转到url/xs_main.aspx?xh=学号样式的个人主页,所以用curl时要配置好header,不然会报错。

  5. 用户输入
    因为只是做演示,所以没有对用户输入的数据进行过滤。


自认水平非常一般,但是把模拟登陆过程记录在此,当是笔记。

附上:测试地址
完整代码稍后会放在Github.