在Python中用Request庫模擬登陸(三):Discuz論壇(未加密,有驗證碼,有隱藏驗證)

Discuz的官方站爲例。直接點擊網頁右上角的登陸按鈕,會彈出一個帶驗證碼的登陸窗口。輸入驗證碼以後,會檢查驗證碼是否正確。而後登陸。首先,經過抓包分析,這些過程瀏覽器和服務器交換了哪些數據。javascript

 

 

抓包分析

整個過程產生了5條數據:php

第一個是GET請求,返回了一段html代碼html

<div id="main_messaqge_LZH8S">
<div id="layer_login_LZH8S">
<h3 class="flb">
<em id="returnmessage_LZH8S">
用戶登陸</em>
<span><a href="javascript:;" class="flbc" onclick="hideWindow('login', 0, 1);" title="關閉">關閉</a></span>
</h3>
<form method="post" autocomplete="off" name="login" id="loginform_LZH8S" class="cl" onsubmit="pwdclear = 1;ajaxpost('loginform_LZH8S', 'returnmessage_LZH8S', 'returnmessage_LZH8S', 'onerror');return false;" action="member.php?mod=logging&amp;action=login&amp;loginsubmit=yes&amp;handlekey=login&amp;loginhash=LZH8S">
<div class="c cl">
<input type="hidden" name="formhash" value="41969484" />
<input type="hidden" name="referer" value="http://www.discuz.net/forum.php" />
<div class="rfm">
<table>
<tr>
<th>
<span class="login_slct">
<select name="loginfield" style="float: left;" width="45" id="loginfield_LZH8S">
<option value="username">用戶名</option>
<option value="email">Email</option>
</select>
</span>
</th>
<td><input type="text" name="username" id="username_LZH8S" autocomplete="off" size="30" class="px p_fre" tabindex="1" value="" /></td>
<td class="tipcol"><a href="member.php?mod=register">當即註冊</a></td>
</tr>
</table>
</div>
<div class="rfm">
<table>
<tr>
<th><label for="password3_LZH8S">密碼:</label></th>
<td><input type="password" id="password3_LZH8S" name="password" onfocus="clearpwd()" size="30" class="px p_fre" tabindex="1" /></td>
<td class="tipcol"><a href="javascript:;" onclick="display('layer_login_LZH8S');display('layer_lostpw_LZH8S');" title="找回密碼">找回密碼</a></td>
</tr>
</table>
</div>
<div class="rfm">
<table>
<tr>
<th>安全提問:</th>
<td><select id="loginquestionid_LZH8S" width="213" name="questionid" onchange="if($('loginquestionid_LZH8S').value > 0) {$('loginanswer_row_LZH8S').style.display='';} else {$('loginanswer_row_LZH8S').style.display='none';}">
<option value="0">安全提問(未設置請忽略)</option>
<option value="1">母親的名字</option>
<option value="2">爺爺的名字</option>
<option value="3">父親出生的城市</option>
<option value="4">您其中一位老師的名字</option>
<option value="5">您我的計算機的型號</option>
<option value="6">您最喜歡的餐館名稱</option>
<option value="7">駕駛執照最後四位數字</option>
</select></td>
</tr>
</table>
</div>
<div class="rfm" id="loginanswer_row_LZH8S"  style="display:none">
<table>
<tr>
<th>答案:</th>
<td><input type="text" name="answer" id="loginanswer_LZH8S" autocomplete="off" size="30" class="px p_fre" tabindex="1" /></td>
</tr>
</table>
</div>
<span id="seccode_cSA"></span>        
<script type="text/javascript" reload="1">updateseccode('cSA', '<div class="rfm"><table><tr><th><sec>: </th><td><sec><br /><sec></td></tr></table></div>', 'member::logging');</script>


<div class="rfm  bw0">
<table>
<tr>
<th></th>
<td><label for="cookietime_LZH8S"><input type="checkbox" class="pc" name="cookietime" id="cookietime_LZH8S" tabindex="1" value="2592000"  />自動登陸</label></td>
</tr>
</table>
</div>

<div class="rfm mbw bw0">
<table width="100%">
<tr>
<th>&nbsp;</th>
<td>
<button class="pn pnc" type="submit" name="loginsubmit" value="true" tabindex="1"><strong>登陸</strong></button>
</td>
<td>
</td>
</tr>
</table>
</div>

<div class="rfm bw0 ">
<hr class="l" />
<table>
<tr>
<th>快捷登陸:</th>
<td>

<a href="http://www.discuz.net/connect.php?mod=login&op=init&referer=http%3A%2F%2Fwww.discuz.net%2Fforum.php&statfrom=login" target="_top" rel="nofollow"><img src="static/image/common/qq_login.gif" class="vm" /></a>


<a href="plugin.php?id=wechat:login"><img src="source/plugin/wechat/image/wechat_login.png" class="vm" /></a>
</td>
</tr>
</table>
</div>
</div>
</form>
</div>
<div id="layer_lostpw_LZH8S" style="display: none;">
<h3 class="flb">
<em id="returnmessage3_LZH8S">找回密碼</em>
<span><a href="javascript:;" class="flbc" onclick="hideWindow('login')" title="關閉">關閉</a></span>
</h3>
<form method="post" autocomplete="off" id="lostpwform_LZH8S" class="cl" onsubmit="ajaxpost('lostpwform_LZH8S', 'returnmessage3_LZH8S', 'returnmessage3_LZH8S', 'onerror');return false;" action="member.php?mod=lostpasswd&amp;lostpwsubmit=yes&amp;infloat=yes">
<div class="c cl">
<input type="hidden" name="formhash" value="41969484" />
<input type="hidden" name="handlekey" value="lostpwform" />
<div class="rfm">
<table>
<tr>
<th><span class="rq">*</span><label for="lostpw_email">Email:</label></th>
<td><input type="text" name="email" id="lostpw_email" size="30" value=""  tabindex="1" class="px p_fre" /></td>
</tr>
</table>
</div>
<div class="rfm">
<table>
<tr>
<th><label for="lostpw_username">用戶名:</label></th>
<td><input type="text" name="username" id="lostpw_username" size="30" value=""  tabindex="1" class="px p_fre" /></td>
</tr>
</table>
</div>

<div class="rfm mbw bw0">
<table>
<tr>
<th></th>
<td><button class="pn pnc" type="submit" name="lostpwsubmit" value="true" tabindex="100"><span>提交</span></button></td>
</tr>
</table>
</div>
</div>
</form>
</div>
</div>

<div id="layer_message_LZH8S" style="display: none;">
<h3 class="flb" id="layer_header_LZH8S">
<em>用戶登陸</em>
<span><a href="javascript:;" class="flbc" onclick="hideWindow('login')" title="關閉">關閉</a></span>
</h3>
<div class="c"><div class="alert_right">
<div id="messageleft_LZH8S"></div>
<p class="alert_btnleft" id="messageright_LZH8S"></p>
</div>
</div>

<script type="text/javascript" reload="1">
var pwdclear = 0;
function initinput_login() {
document.body.focus();
if($('loginform_LZH8S')) {
$('loginform_LZH8S').username.focus();
}
simulateSelect('loginfield_LZH8S');
}
initinput_login();

function clearpwd() {
if(pwdclear) {
$('password3_LZH8S').value = '';
}
pwdclear = 0;
}
</script>
登陸窗口

看起來就是登陸窗口。java

特別注意到,這段代碼中有web

loginhash=LZH8S
<input type="hidden" name="formhash" value="41969484" />

'LZH8S'在代碼中頻繁出現,formhash出現兩次。ajax

刷新以後,loginhash和formhash發生了變化。瀏覽器

第二個GET請求返回了一段JavaScript代碼安全

 1 if($('seccode_cSA')) {
 2     if(!$('vseccode_cSA')) {
 3         var sectpl = seccheck_tpl['cSA'] != '' ? seccheck_tpl['cSA'].replace(/<hash>/g, 'codecSA') : '';
 4         var sectplcode = sectpl != '' ? sectpl.split('<sec>') : Array('<br />',': ','<br />','');
 5         var string = '<input name="seccodehash" type="hidden" value="cSA" /><input name="seccodemodid" type="hidden" value="member::logging" />' + sectplcode[0] + '驗證碼' + sectplcode[1] + '<input name="seccodeverify" id="seccodeverify_cSA" type="text" autocomplete="off" style="ime-mode:disabled;width:100px" class="txt px vm" onblur="checksec(\'code\', \'cSA\', 0, null, \'member::logging\')" />' +
 6             ' <a href="javascript:;" onclick="updateseccode(\'cSA\');doane(event);" class="xi2">換一個</a>' +
 7             '<span id="checkseccodeverify_cSA"><img src="' + STATICURL + 'image/common/none.gif" width="16" height="16" class="vm" /></span>' +
 8             sectplcode[2] + '<span id="vseccode_cSA">請輸入下面動畫圖片中的字符<br /><img onclick="updateseccode(\'cSA\')" width="100" height="35" src="misc.php?mod=seccode&update=18644&idhash=cSA" class="vm" alt="" /></span>' + sectplcode[3];
 9         evalscript(string);
10         $('seccode_cSA').innerHTML = string;
11     } else {
12         var string = '請輸入下面動畫圖片中的字符<br /><img onclick="updateseccode(\'cSA\')" width="100" height="35" src="misc.php?mod=seccode&update=18644&idhash=cSA" class="vm" alt="" />';
13         evalscript(string);
14         $('vseccode_cSA').innerHTML = string;
15     }
16     
17 }
code info

其中的update值在刷新和點擊換一個驗證碼以後產生變化服務器

src="misc.php?mod=seccode&update=18644&idhash=cSA"

第三個GET請求的頭文件包含cookie

GET http://www.discuz.net/misc.php?mod=seccode&update=18644&idhash=cSA HTTP/1.1
Accept: image/webp,image/*,*/*;q=0.8

根據Accept屬性可知返回的是一張圖片,請求連接中包含了上一條請求的update值。

第4個GET請求的連接爲

GET http://www.discuz.net/misc.php?mod=seccode&action=check&inajax=1&modid=member::logging&idhash=cSA&secverify=e38p 

最後的secverify=e38p爲驗證碼,返回的文本爲

<?xml version="1.0" encoding="gbk"?>
<root><![CDATA[succeed]]></root>

根據連接中的action=check和返回的文本推斷,這是在檢查輸入的驗證碼是否正確。

第5個爲POST請求,headers爲

 1 POST http://www.discuz.net/member.php?mod=logging&action=login&loginsubmit=yes&handlekey=login&loginhash=LZH8S&inajax=1 HTTP/1.1
 2 Host: www.discuz.net
 3 Connection: keep-alive
 4 Content-Length: 200
 5 Cache-Control: max-age=0
 6 Origin: http://www.discuz.net
 7 Upgrade-Insecure-Requests: 1
 8 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
 9 Content-Type: application/x-www-form-urlencoded
10 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
11 Referer: http://www.discuz.net/forum.php
12 Accept-Encoding: gzip, deflate
13 Accept-Language: zh-CN,zh;q=0.8
14 Cookie: t7asq_4ad6_saltkey=X3kj05VV; t7asq_4ad6_lastvisit=1496539605; t7asq_4ad6_nofavfid=1; t7asq_4ad6_ulastactivity=1496722517%7C0; t7asq_4ad6_lastcheckfeed=3051978%7C1496722517; t7asq_4ad6_security_cookiereport=798bNiNKvpmS%2BJb6aMC1CK0u2rBbgm%2Bl4RHOagb%2FADNc1uz1WEc6; t7asq_4ad6_connect_is_bind=0; t7asq_4ad6_forum_lastvisit=D_10_1496722811; pgv_pvi=7116158144; pgv_info=ssi=s5527714008; t7asq_4ad6_seccode=14415.a12e22e835ed3df84a; t7asq_4ad6_lastact=1496730222%09misc.php%09seccode
15 
16 formhash=41969484&referer=http%3A%2F%2Fwww.discuz.net%2Fforum.php&loginfield=username&username=123&password=123&questionid=0&answer=&seccodehash=cSA&seccodemodid=member%3A%3Alogging&seccodeverify=e38p

請求的連接中含有loginhash=LZH8S,提交的數據中含有formhash=41969484和驗證碼seccodeverify=e38p和沒有被加密的用戶名和密碼。

由於用戶名和密碼是隨便輸入的,因此返回的文本爲

<?xml version="1.0" encoding="gbk"?>
<root><![CDATA[登陸失敗,您還能夠嘗試 4 次<script type="text/javascript" reload="1">if(typeof errorhandle_login=='function') {errorhandle_login('登陸失敗,您還能夠嘗試 4 次', {'loginperm':'4'});}</script>]]></root>

下面進行模擬登陸,注意要獲取loginhash、formhash和update的值。

模擬登陸

登陸過程當中的5個請求的headers都不一樣,在模擬請求時,徹底複製抓包到的headers。

定義函數:

 1 import requests
 2 session=requests.session()
 3 
 4 #獲取登陸窗口中的loginhash和formhash
 5 def get_login_window():
 6     url='http://www.discuz.net/member.php?mod=logging&action=login&infloat=yes&handlekey=login&inajax=1&ajaxtarget=fwin_content_login'
 7     headers={'Host':'www.discuz.net','Connection':'keep-alive','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36','X-Requested-With':'XMLHttpRequest','Accept':'*/*','Referer':'http://www.discuz.net/forum.php','Accept-Encoding':'gzip, deflate, sdch','Accept-Language':'zh-CN,zh;q=0.8'}
 8     #清空原來的headers
 9     session.headers.clear()
10     #更新headers
11     session.headers.update(headers)
12     r=session.get(url)
13     #獲取loginhash
14     p=r.text.find('loginhash')+len('loginhash')+1
15     loginhash=r.text[p:p+5]
16     #獲取formhash
17     p=r.text.find('formhash')+len('formhash" value="')
18     formhash=r.text[p:p+8]
19     return (loginhash,formhash)
20 
21 #獲取update
22 def get_code_info():
23     url='http://www.discuz.net/misc.php?mod=seccode&action=update&idhash=cSA&0.3916181418197131&modid=member::logging'
24     r=session.get(url)
25     p=r.text.find('update=')
26     update=r.text[p+7:p+12]
27     return update
28 
29 #獲取驗證碼
30 def get_code(update):
31     url='http://www.discuz.net/misc.php?mod=seccode&update='+update+'&idhash=cSA'
32     headers={'Host':'www.discuz.net','Connection':'keep-alive','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36','Accept':'image/webp,image/*,*/*;q=0.8','Referer':'http://www.discuz.net/forum.php','Accept-Encoding':'gzip, deflate, sdch','Accept-Language':'zh-CN,zh;q=0.8'}
33     session.headers.clear()
34     session.headers.update(headers)
35     r=session.get(url)
36     if(r.content[:3]==b'GIF'):
37         #保存驗證碼圖片
38         file=open('code.gif','wb')
39         file.write(r.content)
40         file.close()
41     else:
42         #打印錯誤信息
43         print(r.text)
44 
45 #檢查驗證碼是否正確
46 #經過人工識別驗證碼code,:)
47 def check_code(code):
48     url='http://www.discuz.net/misc.php?mod=seccode&action=check&inajax=1&modid=member::logging&idhash=cSA&secverify='+code
49     headers={'Host':'www.discuz.net','Connection':'keep-alive','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36','Accept':'image/webp,image/*,*/*;q=0.8','Referer':'http://www.discuz.net/forum.php','Accept-Encoding':'gzip, deflate, sdch','Accept-Language':'zh-CN,zh;q=0.8'}
50     session.headers.clear()
51     session.headers.update(headers)
52     r=session.get(url)
53     return r.text
54 
55 #模擬登陸
56 def login(loginhash,formhash,code,username,password):
57     url='http://www.discuz.net/member.php?mod=logging&action=login&loginsubmit=yes&handlekey=login&loginhash='+loginhash+'&inajax=1'
58     data={'formhash':formhash,
59           'referer':'http://www.discuz.net/forum.php',
60           'loginfield':'username',
61           'username':username,
62           'password':password,
63           'questionid':'0',
64           'answer':'',
65           'seccodehash':'cSA',
66           'seccodemodid':'member::logging',
67           'seccodeverify':code}
68     headers={'Host':'www.discuz.net','Connection':'keep-alive','Content-Length':'203','Cache-Control':'max-age=0','Origin':'http://www.discuz.net','Upgrade-Insecure-Requests':'1','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36','Content-Type':'application/x-www-form-urlencoded','Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8','Referer':'http://www.discuz.net/forum.php','Accept-Encoding':'gzip, deflate','Accept-Language':'zh-CN,zh;q=0.8'}
69     session.headers.clear()
70     session.headers.update(headers)
71     r=session.post(url,data)
72     print(r.text)

模擬登陸:

(loginhash,formhash)=get_login_window()
get_code(get_code_info())
code=input()#人工識別 :)
check_code(code)
#[CDATA[succeed]]
login(loginhash,formhash,code,username,password)
#歡迎您回來,如今將轉入登陸前頁面

測試:

此頁面只有在登陸後才能顯示

url='http://www.discuz.net/home.php?mod=space&do=pm'

標題爲 」用戶名 -  Discuz! 官方站 -  Powered by Discuz!「

若是未登陸,則標題爲 」提示信息 -  Discuz! 官方站 -  Powered by Discuz!「

session.headers.clear()
r=session.get(url)
p=r.text.find('<title>')+len('<title>')
print(r.text[p:r.text.find('<',p)])

若是打印出了 」用戶名 -  Discuz! 官方站 -  Powered by Discuz!「,則證實登陸成功。

相關文章
相關標籤/搜索