來(lái)源:麥?zhǔn)寰幊?/p>
作者:kevin。
JS逆向是爬蟲(chóng)的難點(diǎn),是爬蟲(chóng)路上的攔路虎。所謂逆向就是破解網(wǎng)站使用的JS加密算法,拆解相關(guān)的參數(shù)。然后就可以登堂入室了。
本文總結(jié)了JS中最常用的加密算法。正所謂練武不練功,到老一場(chǎng)空。掌握好加密算法就是爬蟲(chóng)技術(shù)的功。如果你是爬蟲(chóng)是認(rèn)真的,認(rèn)真閱讀,收藏,討論。
偽加密算法:base64
Base64是一種用64個(gè)字符來(lái)表示任意二進(jìn)制數(shù)據(jù)的方法。
問(wèn):為什么base64被成為偽加密算法?
答:使用base64將明文變成密文的操作最多算是混淆。沒(méi)有密鑰注入算法,所以只要拿到密文進(jìn)行base64解密就能得到對(duì)應(yīng)的明文。
當(dāng)然還有一種情況就是實(shí)現(xiàn)base64的代碼被改寫(xiě),成為定制版的base64算法。這也沒(méi)關(guān)系,把js代碼摳出來(lái)再用Python去執(zhí)行,也能將密文解密。
識(shí)別方式:由于base64的編碼的特性,要編碼的二進(jìn)制數(shù)據(jù)如果不是3的倍數(shù),最后會(huì)剩下1個(gè)或2個(gè)字節(jié),Base64用x00字節(jié)在末尾補(bǔ)足后,再在編碼的末尾加上1個(gè)或2個(gè)=號(hào),表示補(bǔ)了多少字節(jié)。根據(jù)這個(gè)特性,一般密文結(jié)尾處如果是'='結(jié)尾的,可以先判斷是base64編碼而成。
信息摘要算法:MD5、SHA
摘要算法又稱(chēng)哈希算法、散列算法。它通過(guò)一個(gè)函數(shù),把任意長(zhǎng)度的數(shù)據(jù)轉(zhuǎn)換為一個(gè)長(zhǎng)度固定的數(shù)據(jù)串(通常用16進(jìn)制的字符串表示)。
信息摘要算法信息摘要位數(shù)備注MD5128bit
SHA-1160bit
SHA-224224bitSHA-256的“閹割版”SHA-256256bit
SHA-384384bitSHA-512的“閹割版”SHA-512512bit
摘要算法不能被稱(chēng)為加密算法,因?yàn)樗菃蜗虿僮髅魑牡摹蜗虿僮鞯囊馑季褪牵瑢⒚魑淖兂?lsquo;密文’之后是無(wú)法再將'密文'變成明文(部分信息摘要算法已經(jīng)被突破,可實(shí)現(xiàn)'密'轉(zhuǎn)明)。
基于這種單向操作的特性,摘要算法一般被用于確保信息傳輸完整一致。在爬蟲(chóng)模擬登錄部分這種算法用得會(huì)比較多,舉個(gè)栗子:
假設(shè)我現(xiàn)在要將用戶名是kevin,密碼是123在網(wǎng)頁(yè)上進(jìn)行登錄,瀏覽器會(huì)先通過(guò)js代碼將密碼123轉(zhuǎn)成202cb962ac59075b964b07152d234b70(MD5)再發(fā)送給服務(wù)器。服務(wù)器收到后,知道這個(gè)用戶名為kevin想要登錄,所以從數(shù)據(jù)庫(kù)中調(diào)取了kevin對(duì)應(yīng)的密碼123,然后在服務(wù)器端也對(duì)123進(jìn)行相應(yīng)的加密(哈希)也得到202cb962ac59075b964b07152d234b70,校驗(yàn)兩者一致,服務(wù)器就返回給客服端登錄成功的響應(yīng)。
在實(shí)際JS逆向中哈希函數(shù)的源碼經(jīng)常會(huì)被改寫(xiě),成為定制版哈希函數(shù);還有就是在哈希過(guò)程中,明文會(huì)被加鹽值,遇到些情況就需要認(rèn)真分析源碼。
加鹽:上述栗子中,只對(duì)密碼進(jìn)行 md5 加密是肯定不夠的。聰明的程序員想出了個(gè)辦法,即使用戶的密碼很短,只要在他的短密碼后面加上一段很長(zhǎng)的字符,再計(jì)算 md5 ,那反推出原始密碼就變得非常困難了。加上的這段長(zhǎng)字符,我們稱(chēng)為鹽(Salt),通過(guò)這種方式加密的結(jié)果,我們稱(chēng)為加鹽 Hash。
import hashlib
md5 = hashlib.md5()
md5.update(b'123I_love_salt')
#此處的鹽值為 'I_love_salt'
print(md5.hexdigest())
207a9e3b7f1d0c08f5444c8cb92f8d85 #運(yùn)行結(jié)果
識(shí)別方式:無(wú)論明文數(shù)據(jù)的長(zhǎng)度,經(jīng)過(guò)哈希之后,長(zhǎng)度都是固定的。MD5是32位十六進(jìn)制數(shù),SHA1是40位十六進(jìn)制數(shù),SHA224是56位十六進(jìn)制數(shù)等等。在獲得密文數(shù)據(jù)后,可先判斷是否是十六進(jìn)制數(shù)構(gòu)成,再判斷其長(zhǎng)度是否是常見(jiàn)信息摘要位數(shù)。
對(duì)稱(chēng)加密(加密解密密鑰相同):DES、3DES、AES
對(duì)稱(chēng)加密的核心就是密鑰,拿到密鑰就等于拿到數(shù)據(jù)。也不用去管你是AES還是DES,還有多少輪加密的,拿到密鑰就用python現(xiàn)成的庫(kù)去實(shí)現(xiàn)解密。
AES密鑰長(zhǎng)度密鑰長(zhǎng)度對(duì)應(yīng)的輪數(shù)128bit10192bit12256bit14
識(shí)別方式:密文數(shù)據(jù)的長(zhǎng)度會(huì)隨著明文數(shù)據(jù)的長(zhǎng)度而變化。
非對(duì)稱(chēng)加密(分公鑰私鑰):RSA
對(duì)付像RSA這種非對(duì)稱(chēng)加密算法,我們心中應(yīng)牢記十六字方針——“公鑰加密,私鑰解密。私鑰加密,公鑰解密”。
在非對(duì)稱(chēng)加密算法中,加密與解密的密鑰肯定是不一樣的(一樣的話,就不叫非對(duì)稱(chēng)加密算法了)。牢記“十六字方針”后,我們只要找到‘公鑰’和‘私鑰’就能解密了。當(dāng)然python也有現(xiàn)成的庫(kù)進(jìn)行RSA解密。
識(shí)別方式:RSA公鑰加密會(huì)進(jìn)行類(lèi)似MD5加鹽的操作,所以相同的明文,用相同的公鑰進(jìn)行RSA加密會(huì)生成不同的密文。
RSA的密鑰對(duì)不僅可能存在JS代碼中,還有很有可能會(huì)存在在html文件中。這時(shí)我們進(jìn)行全局搜索關(guān)鍵詞RSA,KEY,encrypt一處處判別就會(huì)有意外收獲。
自定義加密函數(shù)
顧名思義,這種加密解密形式是非常規(guī)的,每個(gè)程序員都可以寫(xiě)屬于自己風(fēng)格的加密方式。對(duì)于逆向這種加密方式,我們還是摳出加密代碼就行了。
這種形式的加密方式應(yīng)該算逆向中最難的,因?yàn)榻饷苷咝枰ダ斫饧用苷叩拇a邏輯,并避開(kāi)加密者設(shè)的各種坑。最后就看誰(shuí)JS玩得更6了。
補(bǔ)充
在實(shí)際逆向項(xiàng)目中MD5、SHA、AES、RSA,自定義加密函數(shù)使用頻率是最多的。而且極有可能會(huì)碰到多種不同加密算法混合使用,例如:網(wǎng)頁(yè)數(shù)據(jù)先base64再AES再進(jìn)行base64,或者解密明文的RSA的密鑰對(duì)被AES加密了等等情況。
DES、3DES、AES、RSA、MD5、SHA傳入的數(shù)據(jù)或者密鑰都是bytes數(shù)據(jù)類(lèi)型,不是bytes數(shù)據(jù)類(lèi)型的需要先轉(zhuǎn)換;密鑰一般是8的倍數(shù)。
附錄參考
下面表格是把明文123用不同算法加密后的密文。相關(guān)的加密方法源碼可以在下面的知識(shí)星球獲得。