https://www.github.com/xiyouMc
首先今天要講的是針對Drcom查詢賬戶URL的解析和抓取數據。
Drcom是大學生宿舍上網普遍使用的聯網客戶端,然而對於自己賬號的信息查詢和修改密碼等都沒有提供一個合理的方式去解決,因此小弟嘗試去編寫實現移動端的 app以方便大學生針對自己drcom賬戶的管理。
架構由來和設計
剛開始我是想直接基於某公司開發的b/s架構去實現客戶端,然而當我去了解該B/S架構的時候才發現去實現C和B/S的架構不合理。爲什麼不合理呢?因爲該B/S架構中當然使用到session機制和圖片驗證機制等等的,要在移動端進行編寫實在是工作量和邏輯有些複雜,並且編寫出來的客戶端勢必會有比較大的累贅。因此我放下當前的工作,仔細思索一個合理的解決這種累贅的方法。 最後我想到了自己去實現server,讓這個server端進行業務邏輯的處理。
當然我實現server第一想到是通過servlet去實現(因爲小弟目前就只會使用jsp/servlet去實現server端)。這種架構的設計,個人取了一個名字,不知道是不是已經有了這個架構設計--------------css架構。 一個客戶端,兩個server端。這裏的兩個server端,相信不用說大家也知道是什麼了。沒錯,就是我的server和某公司的server。(ps:所有的所有,還是因爲小弟不才,搞不到那個數據庫,只能用這種“卑鄙”的手段去解決問題)
核心邏輯
首先大家要了解fiddler這個抓包工具。在這個項目開始之前,我先通過fiddler抓取並大概瞭解到該B/S架構的業務邏輯。
1、對密碼進行加密的方式。
我通過fiddler進行抓包,發現登錄的http請求中會對密碼進行加密,然後每次加密後的密碼都不一樣而且是32位的一個字符串。當時我的第一反應就是該加密方式可能是通過MD5進行加密。然而令我困惑的是該browser端是如何對密碼進行加密的,而且是如何做到每次加密後的密碼不一樣。之後我去看該html的源碼,發現了一個重要的信息。就是這個html中嵌入了javascript,而這個javascript標籤卻不是固定的,是動態的。
<script>
function IsDigit(cCheck)
{
return (('0'<=cCheck) && (cCheck<='9'));
}
function IsAlpha(cCheck)
{
return ((('a'<=cCheck) && (cCheck<='z')) ||(cCheck!='_') || (('A'<=cCheck) && (cCheck<='Z')))
}
function IsaNull(cCheck)
{
return(cCheck != " ")
}
function checkform()
{
var cCheck;
var nIndex;
strUserID = document.LOGIN.name.value;
if (strUserID == "")
{
alert("請輸入用戶帳號");
document.LOGIN.name.focus();
return false;
}
for (nIndex=0; nIndex<strUserID.length; nIndex++)
{
cCheck = strUserID.charAt(nIndex);
if (!(IsDigit(cCheck) || IsAlpha(cCheck) || cCheck=='-' || cCheck=='_' || cCheck=='.'))
{
alert("帳號名只能使用字母、數字以及-、_和.,並且不能使用中文");
document.LOGIN.providername.focus();
return false;
};
}
strUserID = document.LOGIN.serial.value;
queryNum ="null";
if (strUserID == "")
{
alert("請輸入4位隨機碼");
document.LOGIN.serial.focus();
return false;
}
Sessionid ="84b3613e39876c78a177bf0555a4da93";
LOGIN.password.value = LOGIN.password.value + Sessionid;
LOGIN.password.value = calcMD5(LOGIN.password.value);
LOGIN.submit();
}
</script>
加密方式就是上面顯示的。
之後我首先抓包獲取一個登錄請求的參數中加密後的密碼,然後獲取該sessionid,最後通過自己的md5加密算法對正確的密碼進行加密獲取一個32位加密後的字符串。通過匹配,我發現該密碼和http請求中的密碼參數完全符合。之後我就確定了我的加密方式和該browser端的加密方式完全一樣。
每次請求主頁的時候,對該html頁面進行解析,獲取sessionid然後登陸的時候通過md5進行加密。這樣就解決了對密碼進行加密的工作。
2、該邏輯中使用到了session。
session這個技術也是我這次剛接觸到的。
session:
在編程裏是會話的意思 Session 對象存儲特定用戶會話所需的信息。這樣,當用戶在應用程序的 Web 頁之間跳轉時,存儲在 Session 對象中的變量將不會丟失,而是在整個用戶會話中一直存在下去。 當用戶請求來自應用程序的 Web 頁時,如果該用戶還沒有會話,則 Web 服務器將自動創建一個 Session 對象。當會話過期或被放棄後,服務器將終止該會話。 Session 對象最常見的一個用法就是存儲用戶的首選項。例如,如果用戶指明不喜歡查看圖形,就可以將該信息存儲在 Session 對象中。有關使用 Session 對象的詳細信息,請參閱“ASP 應用程序”部分的“管理會話”。 注意 會話狀態僅在支持 cookie 的瀏覽器中保留。
針對該browser端,其中使用到了session和圖片驗證。之後我查詢資料,並自行去實現圖片驗證登錄,或者說是session登錄驗證。實現原理: 第一次請求服務端會產生一個session放在<set-cookies>中response給瀏覽器,獲取圖片的時候必須將該session作爲cookies發送給服務端,這個時候服務端做的工作就是首先隨機產生一個四位數然後將該數字作爲值設置給session,也就是將session和隨機碼進行綁定,這樣做的目的是在登錄的時候服務端可以判斷該四位隨機數是否正確。
3、重定向。
重定向狀態碼也就是3xx. 針對這個架構,進行http請求的時候如果session和圖片驗證都正確的話,狀態碼會是302,這個問題,當時也糾結了我好長時間。 因爲在代碼中如果不判斷狀態碼的話,請求一直都是一個頁面。 當時我一直以爲是session的原因。 302真是個神奇的狀態碼,哈哈。回到正文,如果賬號 密碼 session 和圖片驗證都正確的話,會進行重定向,包頭會有一個location,這個location就是要跳轉的頁面.
針對該架構要注意的一點就是每一個http請求都必須在請求頭增加cookie鍵,值就是第一次產生的session。
附加:
客戶端的編寫邏輯
主界面首先對獲取圖片的api進行請求,該接口會返回session,然後保存在後面的請求中都加上session這個參數。
源碼:
https://github.com/xiyouMc/DrcomClient
https://github.com/xiyouMc/DrcomServer
Thanks for your reading,by Mc.
希望大家可以follow我的Github.以後相互交流技術。感謝你們的star。