网易云音乐评论加密解析
寫在前面的話:
本文是承接上一篇博客https://blog.csdn.net/bicheng4769/article/details/80802184中對(duì)網(wǎng)易云音樂中獲取評(píng)論所需要的兩個(gè)參數(shù)params和encSecKey的進(jìn)一步分析和討論。主要內(nèi)容包括從一開始尋找參數(shù),到如何獲取參數(shù)加密的方式,到如何通過java實(shí)現(xiàn)加密算法的過程。
你能學(xué)到的內(nèi)容:AES加密、抓包工具使用、java中如何使用AES。
本文利用java爬取該歌曲所有用戶的評(píng)論數(shù)據(jù)。以歌曲周董的告白氣球?yàn)槔?#xff0c;利用chrome F12查找獲取評(píng)論的api,然后再基于AES算法對(duì)參數(shù)進(jìn)行加密。最后通過webmagic成功獲取歌曲的所有評(píng)論。本文部分算法參考知乎,全部代碼在github地址上
Chrome F12查找API
進(jìn)入https://music.163.com/#/song?id=418603077,F12打開DevTools工具頁面,找到和評(píng)論相關(guān)的數(shù)據(jù)請(qǐng)求name為R_SO_4_418603077csrf_token=3e89b2e6840298e76bfc0c7dbfad1627的post請(qǐng)求,如下所示:
查看該請(qǐng)求的詳細(xì)內(nèi)容,request Header如下所示:
那么,最終我們需要獲取的數(shù)據(jù)的api接口 以及參數(shù)都已經(jīng)知道了
API:https://music.163.com/weapi/v1/resource/comments/R_SO_4_418603077csrf_token=137ee9288282cdeb180c395d0d4ca1d6
請(qǐng)求方式:POST
請(qǐng)求內(nèi)容類型:application/x-www-form-urlencoded
請(qǐng)求參數(shù):params、encSecKey
顯示,我們下面主要任務(wù)就是要獲取到params和encSecKey的值。從當(dāng)前的值可以看出,這是加密后的內(nèi)容,毫無疑問肯定是通過js加密的。而且,我們可以從第一張圖的Initiator可以看出這兩個(gè)參數(shù)是通過core.js這個(gè)js文件算出來。因此,我們下一步計(jì)劃就是分析core.js的內(nèi)容。
分析Core.js
下載core.js之后,我們打開js文件,一共1.6w行。。。。。。。不過沒關(guān)系,我們只需要關(guān)注參數(shù)出現(xiàn)的幾行就ok。查找一下全文,我們可以看到params和encSeckey同時(shí)出現(xiàn)在這位置:
最終都是通過 windows.asrsea這個(gè)函數(shù)獲取的,我們可以看到有4個(gè)參數(shù),一臉懵逼。這是啥玩意兒,不過沒關(guān)系,我們可以線上調(diào)試一下看看四個(gè)參數(shù)是什么內(nèi)容。線上調(diào)試工具我使用filddler。原理就是將本地的js替換線上加載的js文件,這樣就可以調(diào)試輸出這4個(gè)參數(shù)值。本地js文件加上幾行代碼,如圖所示:
打開fiddler,找到autoResponder,添加Rule,導(dǎo)入本地js文件最終頁面如下圖所示:
然后重新刷新頁面,我們可以看到控制臺(tái)已經(jīng)有內(nèi)容輸出
。如下圖所示:
第一個(gè)參數(shù)是一個(gè)json格式的:{rid: "R_SO_4_418603077",offset: "0",total: "true",limit: "20",csrf_token: ""}
rid的值就是R_SO_4 加上歌曲id;offset就是(評(píng)論頁數(shù)-1)*20;total在第一頁就是true,其余都是false。(大家可以根據(jù)不同的歌曲和翻頁數(shù)多試幾次)。
第二個(gè)參數(shù):
010001
第三個(gè)參數(shù):
00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7
第四個(gè)參數(shù):
0CoJUm6Qyw8W8jud
到此4個(gè)參數(shù)的值我們都已經(jīng)知道了,直接用就可以了。下面的問題是 看看windows.asrsea是如何處理的。定位到這個(gè)函數(shù),發(fā)現(xiàn)他其實(shí)就是叫d的函數(shù),如下圖所示:
我們一行一行的看吧。第一行算了,第二行i就是一個(gè)長(zhǎng)度為16的隨機(jī)的字符串,既然是隨機(jī)的話,我們直接讓i為16個(gè)F。
這個(gè)函數(shù)返回一個(gè)h對(duì)象,有2個(gè)屬性 encText和encSeckey。很明顯encText就是我們需要的params。我們可以看到params是經(jīng)過b函數(shù)2次處理,ensSeckey是經(jīng)過一次c函數(shù)處理,所以我們要看看b函數(shù)和c函數(shù)進(jìn)行了什么操作,如圖:
b函數(shù)其實(shí)就是一個(gè)AES加密函數(shù),一共經(jīng)過2次加密:第一次加密:對(duì)d內(nèi)容進(jìn)行加密,key是第四個(gè)參數(shù);第二次加密:對(duì)第一次加密的結(jié)果內(nèi)容進(jìn)行加密,key是i(也就是16個(gè)F)。而且在b函數(shù)中我們可以看到有個(gè)0102030405060708,這是AES加密算法的偏移量。模式是CBC模式。
c函數(shù)沒看懂啥意思,但是看不懂沒關(guān)系,我們從參數(shù)入手,c函數(shù)三個(gè)參數(shù)分別是i、第二個(gè)參數(shù)e(010001)、第三個(gè)參數(shù)是e。都是固定值,所以這個(gè)encSecKey對(duì)于我們來說是一個(gè)固定值,抄一個(gè)下來就可以直接用了。我這里i是16個(gè)f,所以encSecKey的值就是:
直接用就ok。
java實(shí)現(xiàn)AES加密:
幾個(gè)知識(shí)點(diǎn)大家先了解一下:
- AES加密算法
AES(Advanced Encryption Standard)對(duì)稱加密算法是一種高級(jí)數(shù)據(jù)加密標(biāo)準(zhǔn),可有效抵制針對(duì)DES的攻擊算法。特點(diǎn):密鑰建立時(shí)間短、靈敏性好、內(nèi)存需求低、安全性高。AES使用固定長(zhǎng)度的密鑰,而不是變長(zhǎng)密碼。必須將密碼轉(zhuǎn)成密鑰才能在AES中使用它們。
- 對(duì)稱加密
對(duì)稱加密指的就是加密和解密使用同一個(gè)秘鑰,所以叫做對(duì)稱加密。對(duì)稱加密只有一個(gè)秘鑰,作為私鑰。
常見的對(duì)稱加密算法:DES,AES,3DES等等。
- 非對(duì)稱加密
非對(duì)稱加密指的是:加密和解密使用不同的秘鑰,一把作為公開的公鑰,另一把作為私鑰。公鑰加密的信息,只有私鑰才能解密。私鑰加密的信息,只有公鑰才能解密。
常見的非對(duì)稱加密算法:RSA,ECC
- AES工作模式
我們對(duì)密碼加密不是一個(gè)個(gè)加密,而是分塊加密,叫做密碼塊,工作模式就是對(duì)密碼塊進(jìn)行處理的方式。
ECB:加密前根據(jù)加密塊大小(如AES為128位)分成若干塊,之后將每塊使用相同的密鑰單獨(dú)加密,解密同理。
CBC:CBC模式對(duì)于每個(gè)待加密的密碼塊在加密前會(huì)先與前一個(gè)密碼塊的密文異或然后再用加密器加密。第一個(gè)明文塊與一個(gè)叫初始化向量的數(shù)據(jù)塊異或。
CFB:與ECB和CBC模式只能夠加密塊數(shù)據(jù)不同,CFB能夠?qū)K密文(Block Cipher)轉(zhuǎn)換為流密文(Stream Cipher)。CFB的加密工作分為兩部分:將一前段加密得到的密文再加密;再將第1步加密得到的數(shù)據(jù)與當(dāng)前段的明文異或。
OFB:OFB是先用塊加密器生成密鑰流(Keystream),然后再將密鑰流與明文流異或得到密文流,解密是先用塊加密器生成密鑰流,再將密鑰流與密文流異或得到明文,由于異或操作的對(duì)稱性所以加密和解密的流程是完全一樣的。
- AES填充方式
在分組加密算法中,我們要對(duì)原文進(jìn)行分組,然后再對(duì)分組內(nèi)容進(jìn)行加密,組裝密文。其中有一步是分組,如何分組?假設(shè)現(xiàn)在數(shù)據(jù)長(zhǎng)度不是16的整數(shù)倍,怎么分?所以,我們要對(duì)原文進(jìn)行填充,將原文填充到16的整數(shù)倍。
NoPadding:不填充,如果原文不是16的整數(shù)倍就報(bào)錯(cuò)。
PKCS5Padding:數(shù)據(jù)少幾個(gè)就填充幾。
PaddingMode.Zeros:缺多少就補(bǔ)充多少個(gè)0。
當(dāng)補(bǔ)充成16的整數(shù)倍后,還需要再補(bǔ)充16個(gè)字節(jié),一定要比原來的多。
java內(nèi)部已經(jīng)給我們提供了加密解密的類。大部分都在 crypto這個(gè)包下。主要用到Cipher和SecretKeySpec2個(gè)類。先上代碼:
public static String AESEncrypt(String content,String sKey) { try {byte[] encryptedBytes;byte[] byteContent = content.getBytes("UTF-8");//獲取cipher對(duì)象,getInstance("算法/工作模式/填充模式")Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//采用AES方式將密碼轉(zhuǎn)化成密鑰SecretKeySpec secretKeySpec = new SecretKeySpec(sKey.getBytes(), "AES");//初始化偏移量IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());//cipher對(duì)象初始化 init(“加密/解密,密鑰,偏移量”)cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);//按照上面定義的方式對(duì)數(shù)據(jù)進(jìn)行處理。encryptedBytes = cipher.doFinal(byteContent);return new String(Base64Utils.encode(encryptedBytes), "UTF-8"); } catch (NoSuchAlgorithmException e) {e.printStackTrace(); } catch (NoSuchPaddingException e) {e.printStackTrace(); } catch (InvalidKeyException e) {e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) {e.printStackTrace(); } catch (BadPaddingException e) {e.printStackTrace(); } catch (IllegalBlockSizeException e) {e.printStackTrace(); } catch (UnsupportedEncodingException e) {e.printStackTrace(); } return null; }到此,加密算法基本完成,我們可以自己根據(jù)歌曲id構(gòu)建對(duì)應(yīng)的參數(shù)。
WebMagic爬取網(wǎng)易云音樂評(píng)論:
直接上代碼:
/*** * 密鑰 */ private static String sKey = "0CoJUm6Qyw8W8jud"; @Override public void process(Page page) { Request request = new Request("https://music.163.com/weapi/v1/resource/comments/R_SO_4_" + songId + "?csrf_token=");request.setMethod("post");request.setRequestBody(HttpRequestBody.form(makePostParam(songId, "true", 1), "UTF-8"));page.addTargetRequest(request); } /*** @param songId 歌曲ID* @param paging 是否第一頁 true 第一頁 其余傳入false* @param nowPageNum 當(dāng)前頁數(shù)* @return*/public static String makeContent(String songId, String paging, int nowPageNum) {int offset;if (nowPageNum < 1) {offset = 20;}offset = (nowPageNum - 1) * 20;String baseContent = "{rid: \"R_SO_4_%s\",offset: \"%d\",total: \"%s\",limit: \"20\",csrf_token: \"\"}";return String.format(baseContent, songId, offset, paging);}/*** 獲取評(píng)論的2個(gè)參數(shù)設(shè)置** @param content* @return*/public Map<String, Object> makePostParam(String content) {Map<String, Object> map = new HashMap<>();map.put("params", MusicEncrypt.AESEncrypt((MusicEncrypt.AESEncrypt(content, sKey)), "FFFFFFFFFFFFFFFF"));map.put("encSecKey", MusicEncrypt.rsaEncrypt());return map;}public Map<String, Object> makePostParam(String songId, String paging, int nowPageNum) {return makePostParam(makeContent(songId, paging, nowPageNum));}附上結(jié)果:
總結(jié)語:
最后總結(jié)一下我們對(duì)加密解析的思路:首先找到api,根據(jù)api的參數(shù)找到j(luò)s的加密算法,了解到加密算法之后,利用java去實(shí)現(xiàn)算法, 然后利用算法構(gòu)建參數(shù),實(shí)現(xiàn)爬蟲。
網(wǎng)上大部分對(duì)網(wǎng)易云音樂熱評(píng)加密解析都是通過python實(shí)現(xiàn),畢竟py做爬蟲才是最正統(tǒng)的,奈何筆者不會(huì)python,只能通過java實(shí)現(xiàn),寫到最后,不禁感慨:還是多學(xué)點(diǎn)好耶。
以上所有的解析過程都參考了知乎一位美女的回答:有興趣的同學(xué)可以看看平胸小仙女
總結(jié)
以上是生活随笔為你收集整理的网易云音乐评论加密解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ppt设置外观样式_ppt怎么设置幻灯片
- 下一篇: [导入]ASP.NET 2.0中Page