關(guān)于vue中間代理和ASE,RSA解密從而實(shí)現(xiàn)對網(wǎng)易云api的偽造請求

0x01 實(shí)現(xiàn)步驟概述

技術(shù)棧:vue + node+es6+stylus
其中包含的庫與模塊:axios酝静、crypto-jsrequestrouter
  • vue框架下前端頁面編寫
  • 本地axios網(wǎng)絡(luò)請求,server端請求轉(zhuǎn)發(fā)
  • 對網(wǎng)易云api加密進(jìn)行分析,偽造矾削,最后獲取信息
  • 整體優(yōu)化,防止請求錯誤導(dǎo)致server異常退出

0x02 vue框架下前端頁面編寫

1.目錄結(jié)構(gòu)
image.png

目錄結(jié)構(gòu)是非常簡單的豁护,組件也非常少哼凯,一共有兩個組件,

  • mHeader.vue組件是一個頭組件楚里,可以在這個組件放入logo或者一些標(biāo)識断部,我這里放入的是一個純色div
  • Search.vue組件是搜索組件,在這個組件內(nèi)進(jìn)行歌曲班缎、歌手等搜索蝴光,也是我們著重編輯的部分
2.Router

為了以后添加更多的頁面組件,這里我們采取router路由的方式來規(guī)劃頁面及頁面間的跳轉(zhuǎn)

export default new Router({
  routes: [
    {
      path: '/Search',
      name: 'Search',
      component: Search//引用Search頁面
    },
    {
      path:'/',
      redirect:'/Search' //重定向达址,跳轉(zhuǎn)到Search頁面
    }
  ]
})
3.核心組件Search.vue
image.png

頁面很簡單蔑祟,主要是一個input框。現(xiàn)在我們希望在鍵入內(nèi)容時沉唠,在下方彈出提示內(nèi)容疆虚,像這樣:


image.png

所以我們?yōu)閕nput框綁定事件,方法有很多種满葛,vue下可以便捷的使用這種方式

<input @input="inputFun" placeholder="搜索感興趣的內(nèi)容" type="text">

其中inputFun就是我們綁定的事件径簿,每當(dāng)input內(nèi)容發(fā)生變化,就會執(zhí)行這個函數(shù)嘀韧。我們在methods中實(shí)現(xiàn)這個方法篇亭。
函數(shù)的具體實(shí)現(xiàn):

methods:{
        inputFun(e){
          this.searchConent = e.target.value  //取出input內(nèi)容
          console.log(this.searchConent)
          if(this.searchConent.length < 1){  //判斷是否為空
            this.info_flag = false           //取消提示框的顯示
            return
          }
          //執(zhí)行查詢
          this.searchSubmit(this.searchConent, () => {  //此時input不為空,執(zhí)行查詢函數(shù)锄贷,callback回調(diào)
            if (this.searchConent.length < 1){
              this.info_flag = false
              return
            }else{
              this.info_flag = true
            }
          })
        },
    ...//其他方法
  }

searchSubmit函數(shù)執(zhí)行api查詢译蒂,以下是searchSubmit函數(shù)注意這里需要使用callback回調(diào),不然會出現(xiàn)問題谊却,不使用callback回掉會造成提示框出現(xiàn)過早蹂随,我們希望請求到數(shù)據(jù)以后再進(jìn)行顯示

searchSubmit(data, callback) {
          search(data).then((res) => {
            if(res.data.code == "200"){
              this.searchInfoJson = res.data.result
              callback()
            }else{
              console.log('error:error')
            }
          })
        }

以上search.vue組件就算是寫完了

0x03 本地axios網(wǎng)絡(luò)請求,server端請求轉(zhuǎn)發(fā)

1. server中間轉(zhuǎn)發(fā)配置

vue在開發(fā)環(huán)境中調(diào)試時因惭,本質(zhì)就是啟動了node服務(wù)器,再用這個node服務(wù)器去啟動vue資源绩衷,那么我們的api請求代理轉(zhuǎn)發(fā)就可以寫在這個默認(rèn)的node服務(wù)器蹦魔,即在webpack.dev.conf.js中配置即可


image.png

這里我們需要在起始位置引入兩個模塊

//引入request模塊
const request = require('request')

//引入APIenc加密模塊
const enc = require('../API_ENC/enc.js')

其中request模塊是一個http請求模塊激率,使用它可以輕松的完成GET、POST等請求勿决,我們用它來向網(wǎng)易云音樂獲取數(shù)據(jù)乒躺。
enc模塊是我們自己編寫的加密模塊,網(wǎng)易云api請求對數(shù)據(jù)進(jìn)行了ASE低缩、RSA加密嘉冒,我們編寫模塊來重構(gòu)數(shù)據(jù)加密。
devServer節(jié)點(diǎn)中建立before(app){}咆繁,在這里面寫http的get和post請求讳推,并通過api的形式傳回前端:

devServer: {
    //此處設(shè)置代理API
    before(app) {
      app.get('/api/test', (req, res) => {
        console.log(req.query.data)
        console.log('{"s":"'+req.query.data+'","limit":"8","csrf_token":""}')
        const h = enc.enc('{"s":"'+req.query.data+'","limit":"8","csrf_token":""}')
        const _data = 'params='+h.encText+'&encSecKey='+h.encSecKey
        //const _data='params=I9poLQX4QhYUqTlGJ0BuBqrBGfjgpwEOy91ZkftCJVKEh2fEs0EMzJOgYGDTmEyz4GAwdhdAeZ3L0oQU%2BCcmJEBODxiqBinxplaKGtUpfp8%3D&encSecKey=cc402fbec71e6483371fdfc6f7e14701f54b8d0b731617803436647fa1ca8db8e77236287d4be8b21336f04d527e10a7948b6da773d3a5de638b0005a194fc6c48fa6e5de32dcf891c388feec4c97ec4c6b3b6bd208c1389d6776d1cbc16425c9e15847bdb42257390030a5b2660ab6d1db81200d4458f9f6d9e6640b7393f16'
        console.log(_data)
        try{
          request.post({
            url:'https://music.163.com/weapi/search/suggest/web?csrf_token=',
            form:_data,
            headers:{
              'Content-Type':'application/x-www-form-urlencoded',
              'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
            }
          }, (error, response) => {
            if(response.body && response.body.length > 1){
              console.log(response.body)
              try{
                res.json({
                  error:0,
                  data:JSON.parse(response.body)
                })
              }catch (e) {
                console.log(e)
              }
            }else{
              console.log('數(shù)據(jù)空')
              res.json({
                error:0,
                data:{}
              })
            }
            //console.log(response.body)
          })
        }catch (e) {

        }
      }),
      app.post('/api/post', (req, res) => {
        res.json({
          errno: 0,
          data: 'helloPost'
        })
      })
    },
    //設(shè)置完畢
...其他代碼  
}

其中的enc模塊就是我們抽象的網(wǎng)易云音樂加密模塊,在后面我們將詳細(xì)著重介紹這個模塊的編寫

image.png

另外需要注意的是請求中的headers需要進(jìn)行配置玩般,否則將不能獲取到數(shù)據(jù)银觅,設(shè)置user-agent和content-type是爬蟲和仿造請求的兩個重要手段,在以后很多情況都要用到坏为。

2. 前端axios請求api配置

當(dāng)然還需要在前端配置api究驴,其中我們使用了axios模塊實(shí)現(xiàn),將axios的get請求封裝成search函數(shù)匀伏,并通過export進(jìn)行暴露洒忧。

import axios from 'axios'

export function search (data) {
  const url = './api/test'
  console.log(data)
  return axios.get(url, {
    params: {
      data:data
    }
  }).then((res) => {
    console.log(res.data)
    return res.data
  })
}

之后,我們便可以在任何組件中輕松的使用這個api够颠,
在search.vue組件中引入

import {search} from '../../api/httpReq'

0x04 對網(wǎng)易云api加密進(jìn)行分析熙侍,偽造,最后獲取信息

首先我們對網(wǎng)易云搜索提示的api進(jìn)行分析摧找,在輸入內(nèi)容前按下F12并轉(zhuǎn)換到Network保持網(wǎng)絡(luò)抓包開啟

image.png

我們可以看到數(shù)據(jù)很多核行,點(diǎn)開最后一個,可以在preview中看到數(shù)據(jù)內(nèi)容
image.png

image.png

Headers可以看到提交的請求數(shù)據(jù)
image.png

請求結(jié)構(gòu)非常簡單蹬耘,但是data部分用到了加密芝雪,既然要偽造,那么就需要模擬加密過程综苔,這里推薦大家使用fiddler惩系,fiddler可以進(jìn)行全局搜索,方便我們逆向加密算法如筛,現(xiàn)在轉(zhuǎn)到fiddler堡牡,刷新網(wǎng)易云頁面,全局搜索encSecKey
image.png

包含關(guān)鍵字的包將會被高亮顯示
image.png

這個包是很可疑的杨刨,這是一個js庫晤柄,里面很可能就是加密算法,現(xiàn)在轉(zhuǎn)到瀏覽器F12中的Source選項(xiàng)中打開這個js庫
image.png

這個按鈕優(yōu)化代碼顯示
image.png

定位到包含encSecKey的位置
image.png

很明顯妖胀,這個就是加密方法了芥颈,現(xiàn)在的主要問題是我們?nèi)绾稳ヌ崛∵@個方法到我們自己的模塊惠勒。其實(shí)很簡單,只要把加密過程走一遍分析他是什么類型的加密爬坑,這樣我們再重構(gòu)加密方法就易如反掌了纠屋。我們下一個斷點(diǎn)看看具體參數(shù)。
image.png

我們在12861行也就是函數(shù)頭部下一個斷點(diǎn)
image.png

斷下來以后我們看到參數(shù)d就是被加密的原始數(shù)據(jù)盾计,而剩下3個參數(shù)都是固定值售担,不發(fā)生變化,可以視之為鹽署辉。
image.png

這三個按鈕分別是步過族铆,步入,和執(zhí)行到返回涨薪,善用調(diào)試骑素,可以讓問題變得簡單。
我們一步一步跟下去刚夺,發(fā)現(xiàn)執(zhí)行的順序是
image.png

所以只要模擬a,b,c這三個函數(shù)即可

function a(a) {//主要是取隨機(jī)生成鹽
        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
        for (d = 0; a > d; d += 1)
            e = Math.random() * b.length,
            e = Math.floor(e),
            c += b.charAt(e);
        return c
    }
    function b(a, b) {//數(shù)據(jù)進(jìn)行AES加密
        var c = CryptoJS.enc.Utf8.parse(b)
          , d = CryptoJS.enc.Utf8.parse("0102030405060708")
          , e = CryptoJS.enc.Utf8.parse(a)
          , f = CryptoJS.AES.encrypt(e, c, {
            iv: d,
            mode: CryptoJS.mode.CBC
        });
        return f.toString()
    }
    function c(a, b, c) {//鹽進(jìn)行RSA加密
        var d, e;
        return setMaxDigits(131),
        d = new RSAKeyPair(b,"",c),
        e = encryptedString(d, a)
    }
    function d(d, e, f, g) {
        var h = {}
          , i = a(16);
        return h.encText = b(d, g),
        h.encText = b(h.encText, i),
        h.encSecKey = c(i, e, f),
        h
    }

還原b方法可以直接用献丑,不過需要注意引用Crypto-js庫,這是一個專門的AES加密解密庫侠姑。
而還原c方法則不可以直接復(fù)制了创橄,因?yàn)檫@里的c方法并不是正常的RSA加密,詳細(xì)的不同地方同學(xué)們可以深入調(diào)試莽红,可以重新自己寫c方法的加密妥畏,在這里不做過多介紹了,除了重寫加密方法外安吁,其實(shí)還有一種簡單的方法醉蚁,就是根據(jù)c函數(shù)的調(diào)用,找出對應(yīng)得方法而依次調(diào)用鬼店,我這里也是采取了這種方法网棍,直接從第12412行第12834行全部粘貼到我們的模塊,經(jīng)過測試這種方式是完全正確的妇智。
所以整個enc模塊看起來是這樣的:

const CryptoJS = require('crypto-js')
function RSAKeyPair(a, b, c) {
  this.e = biFromHex(a),
    this.d = biFromHex(b),

//......此處省略復(fù)制的代碼

lowBitMasks = new Array(0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535);
console.log('LOADING--------------------------------------------------------------------------')
function c(a, b, c) {
  var d, e;
  return setMaxDigits(131),
    d = new RSAKeyPair(b,"",c),
    e = encryptedString(d, a)
}
function a(a) {
  var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
  for (d = 0; a > d; d += 1)
    e = Math.random() * b.length,
      e = Math.floor(e),
      c += b.charAt(e);
  return c
}
function b(a, b) {
    var c = CryptoJS.enc.Utf8.parse(b),
    d = CryptoJS.enc.Utf8.parse("0102030405060708"),
    e = CryptoJS.enc.Utf8.parse(a),
    f = CryptoJS.AES.encrypt(e, c, {
        iv: d,
        mode: CryptoJS.mode.CBC
    });
    return f.toString()
}
function enc(data){
  var h = {}
  var i = a(16)
  h.encText = b(data, '0CoJUm6Qyw8W8jud')
  h.encText = b(h.encText, i)
  var e = '010001'
  var f = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
  h.encSecKey = c(i, e, f);
  //console .log('encText:' + h.encText + '\n' + 'encSecKey:' + h.encSecKey)
  return h
}
/*
test:
APIenc('{"s":"周杰倫","limit":"8","csrf_token":""}')
*/
//console.log(enc('{"s":"周杰倫","limit":"8","csrf_token":""}'))
exports.enc = enc

到此滥玷,網(wǎng)易云api的加密分析就完成了,enc模塊的編寫也全部完成巍棱。

0x05 整體優(yōu)化惑畴,防止請求錯誤導(dǎo)致server異常退出

1. server部分優(yōu)化

在我測試的時候,會經(jīng)常發(fā)生server異常崩潰死掉的情況航徙,主要原因是請求的數(shù)據(jù)返回空如贷,而我們想要將之解析為json格式,那么將會拋出一個解析格式不正確的錯誤。所以需要加之判斷杠袱,判斷請求數(shù)據(jù)是否為空泻红,為空則返回空數(shù)據(jù),不為空則進(jìn)行解析霞掺。

if(response.body && response.body.length > 1){//數(shù)據(jù)不為空
              console.log(response.body)
              try{//嘗試進(jìn)行解析
                res.json({
                  error:0,
                  data:JSON.parse(response.body)
                })
              }catch (e) {
                console.log(e)
              }
            }else{
              console.log('數(shù)據(jù)空')
              res.json({
                error:0,
                data:{}
              })
            }
2. 前端優(yōu)化

前端我們創(chuàng)建了一個info_flag標(biāo)志位來規(guī)定是否對提示框進(jìn)行顯示,然而info_flag標(biāo)志位的true false切換時機(jī)變得尤為重要讹躯,為了更好的用戶體驗(yàn)菩彬,我們希望在生成數(shù)據(jù)以后進(jìn)行提示框的現(xiàn)實(shí),所以這里就用到了callback回調(diào)潮梯,在請求到數(shù)據(jù)以后進(jìn)行回調(diào)骗灶,此時再進(jìn)行標(biāo)志位的切換。

searchSubmit(data, callback) {//獲取數(shù)據(jù)函數(shù)
          search(data).then((res) => {
            if(res.data.code == "200"){
              this.searchInfoJson = res.data.result
              callback()//獲取到數(shù)據(jù)以后再執(zhí)行callback函數(shù)來顯示info框
            }else{
              console.log('error:error')
            }
          })
        }

至此秉馏,所有的前端和server中間代理就完成了

cnpm run dev //使用此語句來運(yùn)行吧耙旦!

0x06 效果演示

搜索演示.gif

點(diǎn)擊github給個星星吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市萝究,隨后出現(xiàn)的幾起案子免都,更是在濱河造成了極大的恐慌,老刑警劉巖帆竹,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绕娘,死亡現(xiàn)場離奇詭異,居然都是意外死亡栽连,警方通過查閱死者的電腦和手機(jī)险领,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秒紧,“玉大人绢陌,你說我怎么就攤上這事∪刍郑” “怎么了脐湾?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绩聘。 經(jīng)常有香客問我沥割,道長,這世上最難降的妖魔是什么凿菩? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任机杜,我火速辦了婚禮,結(jié)果婚禮上衅谷,老公的妹妹穿的比我還像新娘椒拗。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布蚀苛。 她就那樣靜靜地躺著在验,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堵未。 梳的紋絲不亂的頭發(fā)上腋舌,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機(jī)與錄音渗蟹,去河邊找鬼块饺。 笑死,一個胖子當(dāng)著我的面吹牛雌芽,可吹牛的內(nèi)容都是我干的授艰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼世落,長吁一口氣:“原來是場噩夢啊……” “哼淮腾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起屉佳,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谷朝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后忘古,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徘禁,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年髓堪,在試婚紗的時候發(fā)現(xiàn)自己被綠了送朱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡干旁,死狀恐怖驶沼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情争群,我是刑警寧澤回怜,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站换薄,受9級特大地震影響玉雾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轻要,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一复旬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冲泥,春花似錦驹碍、人聲如沸壁涎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怔球。三九已至,卻和暖如春浮还,著一層夾襖步出監(jiān)牢的瞬間竟坛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工钧舌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留流码,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓延刘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親六敬。 傳聞我的和親對象是個殘疾皇子碘赖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容