整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          JS 解密和混淆破解

          JS 解密和混淆破解

          們已經(jīng)學(xué)到很多反爬機(jī)制以及相應(yīng)的反反爬策略。使用那些手段,其實(shí)已經(jīng)完全可以完成絕大多數(shù)的爬蟲任務(wù)。但是,還是有極個(gè)別的情況下,會(huì)出現(xiàn)諸如 JS 加密和 JS 混淆之類的高深反爬機(jī)制。

          如果不幸遇到這種反爬機(jī)制,一個(gè)明智之舉是給站長點(diǎn)個(gè)贊,然后恭恭敬敬選擇放棄,去別的地方找數(shù)據(jù)。

          當(dāng)然,還是那句話,我們可以選擇不爬,但是對(duì)付 JS 加密和 JS 混淆的方法卻不可以不會(huì)。

          這里就以中國空氣質(zhì)量在線檢測平臺(tái)為例,介紹 JS 加密和 JS 混淆的實(shí)現(xiàn)和破解方法。

          要爬取的網(wǎng)站:https://www.aqistudy.cn/html/city_detail.html

          這個(gè)網(wǎng)站正在升級(jí),所以頁面無法正常顯示。這也意味著這個(gè)網(wǎng)站本身的 JS 解密是有問題的(如果沒問題就能顯示了),所以最后我們并不能完全解析出數(shù)據(jù)來。雖然如此,這個(gè)網(wǎng)站仍然是學(xué)習(xí) JS 加密和 JS 混淆的相當(dāng)不錯(cuò)的平臺(tái)。

          閑話少說,開始干活!

          首先瀏覽器打開網(wǎng)頁,并打開調(diào)試臺(tái)的抓包工具。修改查詢條件(城市的名稱 + 時(shí)間范圍),然后點(diǎn)擊查詢按鈕,捕獲點(diǎn)擊按鈕后發(fā)起請(qǐng)求對(duì)應(yīng)的數(shù)據(jù)包。點(diǎn)擊查詢按鈕后,并沒有刷新頁面,顯然發(fā)起的是 ajax 請(qǐng)求。該請(qǐng)求就會(huì)將指定查詢條件對(duì)應(yīng)的數(shù)據(jù)加載到當(dāng)前頁面中(我們要爬取的數(shù)據(jù)就是該 ajax 請(qǐng)求請(qǐng)求到的數(shù)據(jù))。

          分析捕獲到的數(shù)據(jù)包

          • 提取出請(qǐng)求的 url:https://www.aqistudy.cn/apinew/aqistudyapi.php
          • 請(qǐng)求方式:post
          • 請(qǐng)求參數(shù):d: 動(dòng)態(tài)變化一組數(shù)據(jù)(且加密)
          • 響應(yīng)數(shù)據(jù):是加密的密文數(shù)據(jù)

          該數(shù)據(jù)包請(qǐng)求到的是密文數(shù)據(jù),為何在前臺(tái)頁面顯示的卻是原文數(shù)據(jù)呢?

          原來,在請(qǐng)求請(qǐng)求到密文數(shù)據(jù)后,前臺(tái)接受到密文數(shù)據(jù)后使用指定的解密操作(JS 函數(shù))對(duì)密文數(shù)據(jù)進(jìn)行了解密操作,然后將原文數(shù)據(jù)顯示在了前臺(tái)頁面。

          接下來的工作流程:

          首先先處理動(dòng)態(tài)變化的請(qǐng)求參數(shù),動(dòng)態(tài)獲取該參數(shù)的話,就可以攜帶該參數(shù)進(jìn)行請(qǐng)求發(fā)送,將請(qǐng)求到的密文數(shù)據(jù)捕獲到。

        1. 將捕獲到的密文數(shù)據(jù)找到對(duì)應(yīng)的解密函數(shù)對(duì)其進(jìn)行解密即可。
        2. 【重點(diǎn)】需要找到點(diǎn)擊查詢按鈕后對(duì)應(yīng)的 ajax 請(qǐng)求代碼,從這組代碼中就可以破解動(dòng)態(tài)變化的請(qǐng)求參數(shù)和加密的響應(yīng)數(shù)據(jù)對(duì)應(yīng)的相關(guān)操作。
        3. 找 ajax 請(qǐng)求對(duì)應(yīng)的代碼,分析代碼獲取參數(shù) d 的生成方式和加密的響應(yīng)數(shù)據(jù)的解密操作。直接在頁面中,并沒有辦法直接找到發(fā)送 ajax 請(qǐng)求的函數(shù)的,因?yàn)樗约氨环庋b到別的文件中了。我們可以基于火狐瀏覽器定位查詢按鈕綁定的點(diǎn)擊事件。
        4. 抽絲剝繭,首先從 getData 函數(shù)實(shí)現(xiàn)中找尋 ajax 請(qǐng)求對(duì)應(yīng)的代碼。在該函數(shù)的實(shí)現(xiàn)中沒有找到 ajax 代碼,但是發(fā)現(xiàn)了另外兩個(gè)函數(shù)的調(diào)用,getAQIData()getWeatherData()。ajax 代碼一定是存在于這兩個(gè)函數(shù)實(shí)現(xiàn)內(nèi)部。

          另外,這里記住一個(gè)參數(shù),type==’HOUR‘,它的含義是查詢時(shí)間是以小時(shí)為單位。這個(gè)參數(shù)我們后來會(huì)用到。

          接下來我們就去分析 getAQIData()getWeatherData(),爭取能夠找到 ajax 代碼。

          我們找到這兩個(gè)函數(shù)的定義位置,還是沒有找到 ajax 請(qǐng)求代碼。不過我們卻發(fā)現(xiàn)它們同時(shí)調(diào)用了另外一個(gè)函數(shù),getServerData(method,param,func,0.5)。它的參數(shù)的值可以為:

          • method 可以是 ‘GETCITYWEATHER’ 或者 ‘GETDETAIL’
          • params 的值是 {city, type, startTime, endTime},也就是查詢條件
          • func 是一個(gè)匿名函數(shù),看樣子是在處理數(shù)據(jù)。

          下一步當(dāng)然就要找 getServerData 函數(shù)了,看看那個(gè)函數(shù)里面有沒有我們一致想要的發(fā)送 ajax 請(qǐng)求的代碼。

          我們嘗試著在頁面中搜索,卻找不到這個(gè)函數(shù)。很顯然,它是被封裝到其他 js 文件中了。這時(shí),我們可以基于抓包工具做全局搜索。

          好消息是,我們順利找到了 getServerData 函數(shù)!壞消息是,這貨長得一點(diǎn)也不像是函數(shù)。

          這是因?yàn)椋@段 JS 函數(shù)代碼被加密的。這種加密的方式,我們稱為 JS 混淆。

          JS 混淆,也就是對(duì)核心的 JS 代碼進(jìn)行加密。

          JS 反混淆,則是對(duì) JS 加密代碼進(jìn)行解密。

          接下來我們要做的,就是 JS 反混淆,讓這段我們看不懂的東西,顯現(xiàn)出廬山真面目。

          我們用的方法十分簡單粗暴,也就是暴力破解。使用這個(gè)網(wǎng)站就可以實(shí)現(xiàn)對(duì) JS 混淆的暴力破解:https://www.bm8.com.cn/jsConfusion/

          將 getServerData 函數(shù)所在的那一整行代碼都復(fù)制過來,粘貼到這個(gè)網(wǎng)址的文本輸入框中,然后點(diǎn)擊 開始格式化 即可:

          終于,我們看到了 getServerData 的代碼,并且在其中發(fā)現(xiàn)了發(fā)送 ajax 的請(qǐng)求:

          function getServerData(method, object, callback, period) {
              const key=hex_md5(method + JSON.stringify(object));
              const data=getDataFromLocalStorage(key, period);
              if (!data) {
                  var param=getParam(method, object);
                  $.ajax({
                      url: '../apinew/aqistudyapi.php',
                      data: {
                          d: param
                      },
                      type: "post",
                      success: function (data) {
                          data=decodeData(data);
                          obj=JSON.parse(data);
                          if (obj.success) {
                              if (period > 0) {
                                  obj.result.time=new Date().getTime();
                                  localStorageUtil.save(key, obj.result)
                              }
                              callback(obj.result)
                          } else {
                              console.log(obj.errcode, obj.errmsg)
                          }
                      }
                  })
              } else {
                  callback(data)
              }
          }

          從這段代碼中,我們不難得出下面這幾個(gè)信息:

          • ajax 請(qǐng)求成功后獲得到的 data 是加密的響應(yīng)數(shù)據(jù)(就是我們最開始通過抓包工具看到的那一串神秘的相應(yīng)字符串),通過 decodeData(data) 函數(shù),可以將加密的數(shù)據(jù)解密成我們需要的明文數(shù)據(jù)。
          • 發(fā)送請(qǐng)求時(shí)攜帶的參數(shù),也就是 d 對(duì)應(yīng)的值 param 是通過 getParam(method, object) 函數(shù)返回動(dòng)的態(tài)變化的請(qǐng)求參數(shù)。這兩個(gè)參數(shù)我們前面也分析過:參數(shù) method 可以是 ‘GETCITYWEATHER’ 或者 ‘GETDETAIL’參數(shù) object 則為 {city, type, startTime, endTime},是我們的查詢條件我們當(dāng)然還可以繼續(xù)最終下去,刨根問題找到它們究竟是通過什么方式進(jìn)行加密和解密的。然后,使用 Python 代碼,重復(fù)這個(gè)加密和解密的過程,完成請(qǐng)求數(shù)據(jù)的生成和響應(yīng)數(shù)據(jù)的解析過程。

          但是我們并不打算這么做。因?yàn)樵倮^續(xù)深挖下去,難度將會(huì)陡然增加。此時(shí)我們已經(jīng)很疲憊了,如果繼續(xù)下去恐怕要瘋掉。而且,JavaScript 和 Python 畢竟是兩種語言,它們之間的方法和各種包都不相同。JavaScript 能實(shí)現(xiàn)的,Python 未必能夠輕松完成。所以重新寫一個(gè)加密和解密的腳本,并不是明智之舉。

          更好的解決方案是,我們提供請(qǐng)求的明文數(shù)據(jù),通過網(wǎng)站自己的 JS 代碼進(jìn)行加密,得到加密的請(qǐng)求參數(shù)。使用這個(gè)參數(shù),我們發(fā)送請(qǐng)求給服務(wù)端。拿到加密的響應(yīng)數(shù)據(jù)后,再通過網(wǎng)站的 JS 代碼進(jìn)行解密。

          也就是說,我們接下來需要做的就是要調(diào)用兩個(gè) JS 函數(shù) decodeData 和 getParam,并拿到返回結(jié)果即可。

          現(xiàn)在的問題是,在 Python 程序中如何調(diào)用 JS 函數(shù)呢?

          這就涉及到一個(gè)新的概念:JS 逆向。JS 逆向,也就是在 Python 中調(diào)用 JS 函數(shù)代碼。

          能夠?qū)崿F(xiàn) JS 逆向的方式有兩種:

          1. 手動(dòng)將 JS 函數(shù)改寫稱為 Python 函數(shù)并執(zhí)行。
          2. 這種方法我剛剛談過了,并不現(xiàn)實(shí)。因?yàn)?JS 能實(shí)現(xiàn)的,Python 未必能夠輕易實(shí)現(xiàn)。而且畢竟還要重寫函數(shù),比較麻煩。
          3. 使用固定模塊,實(shí)現(xiàn)自動(dòng)逆向(推薦)。
          4. 一個(gè)很好用的實(shí)現(xiàn) JS 逆向的 Python 庫 是 PyExecJS。
          5. PyExecJS 庫用來實(shí)現(xiàn)模擬 JavaScript 代碼執(zhí)行獲取動(dòng)態(tài)加密的請(qǐng)求參數(shù),然后再將加密的響應(yīng)數(shù)據(jù)帶入 decodeData 進(jìn)行解密即可。
          6. PyExecJS 需要在本機(jī)安裝好 nodejs 的環(huán)境。
          7. PyExecJS 的安裝:
          pip install PyExecJS

          接下來,我們就可以生成加密的請(qǐng)求數(shù)據(jù)了。

          首先,把我們解析出來的那串代碼保存到本地,比如名為 code.js 的文件中。在里面我們補(bǔ)充一個(gè)函數(shù),比如名字叫 getPostParamCode,用來發(fā)起我們的數(shù)據(jù)請(qǐng)求。之所以這樣做是因?yàn)槭褂?PyExecJS 調(diào)用 JS 函數(shù)時(shí),傳入的參數(shù)只能是字符串。而 getParam 方法的參數(shù)需要用到 JS 的自定義對(duì)象。

          我們只需在 code.js 中加上下面的代碼即可:

          function getPostParamCode(method, type, city, start_time, end_time) {
              var param={};
              param.type=type;
              param.city=city;
              param.start_time=start_time;
              param.end_time=end_time;
              return getParam(method, param)
          }

          然后,使用 PyExecJS 調(diào)用里面的 getParam 方法,將我們的請(qǐng)求數(shù)據(jù)加密:

          # 模擬執(zhí)行decodeData的js函數(shù)對(duì)加密響應(yīng)數(shù)據(jù)進(jìn)行解密
          import execjs
          import requests
          
          node=execjs.get()
          
          # 請(qǐng)求參數(shù)
          method='GETCITYWEATHER'
          type='HOUR'
          city='北京'
          start_time='2020-03-20 00:00:00'
          end_time='2020-03-25 00:00:00'
          
          # 編譯js代碼
          file='code.js'    # js代碼的路徑
          ctx=node.compile(open(file, encoding='utf-8').read())
          
          # 將請(qǐng)求數(shù)據(jù)加密
          encode_js=f'getPostParamCode("{method}", "{type}", "{city}", "{start_time}", "{end_time}")'
          params=ctx.eval(encode_js)
          
          # 使用加密的參數(shù),發(fā)起post請(qǐng)求
          url='https://www.aqistudy.cn/apinew/aqistudyapi.php'
          response_text=requests.post(url, data={'d': params}).text
          
          # 將響應(yīng)數(shù)據(jù)解密
          decode_js=f'decodeData("{response_text}")'
          decrypted_data=ctx.eval(decode_js)    # 如果順利,返回的將是解密后的原文數(shù)據(jù)
          print(decrypted_data)    # 執(zhí)行會(huì)報(bào)錯(cuò):目前頁面中沒有數(shù)據(jù)。解密函數(shù)只是針對(duì)頁面中原始的數(shù)據(jù)進(jìn)行解密。

          自此,我們完成了 JS 加密和 JS 混淆的處理。這里我們總結(jié)一下這幾個(gè)概念:

          • JS 加密,也就是通過 JS 代碼,將數(shù)據(jù)進(jìn)行加密處理,將明文數(shù)據(jù)變成密文數(shù)據(jù)。如果不能將其解密,密文數(shù)據(jù)將毫無用處。
          • JS 解密:通過 JS 代碼,將加密的數(shù)據(jù)解密,也就是將密文數(shù)據(jù)解析成明文數(shù)據(jù)。JS 解密是 JS 加密的逆過程。
          • JS 混淆:將 JS 代碼(比如 JS 函數(shù))本身進(jìn)行加密。
          • JS 反混淆:將加密了的 JS 代碼解密成常規(guī)的 JS 代碼。通常直接使用暴力破解即可。
          • JS 逆向(重要):通過 Python 代碼調(diào)用 JS 的函數(shù)。

          附,ajax 請(qǐng)求的各個(gè)數(shù)據(jù)的含義:

          頭條號(hào)每天堅(jiān)持更新原創(chuàng)干貨技術(shù)文章,歡迎關(guān)注本頭條號(hào)"Linux學(xué)習(xí)教程",公眾號(hào)名稱“Linux入門學(xué)習(xí)教程"。

          如需學(xué)習(xí)視頻,請(qǐng)復(fù)制以下信息到手機(jī)瀏覽器或電腦瀏覽器上:

          zcwyou.com

          1. 前言

          隨著互聯(lián)網(wǎng)活動(dòng)的增加,網(wǎng)絡(luò)攻擊變得更加復(fù)雜和具有挑戰(zhàn)性。

          毫無疑問,互聯(lián)網(wǎng)用戶的數(shù)據(jù)安全意識(shí)已經(jīng)成倍增長。如果你是站長或博主,保護(hù)用戶的敏感數(shù)據(jù)和隱私不受網(wǎng)絡(luò)罪犯的惡意侵害就成了你的首要責(zé)任。

          在這里,SSL證書在加強(qiáng)您的網(wǎng)站安全性方面起著最有效和最關(guān)鍵的作用。因此,我們很有必要了解SSL的基本知識(shí)。

          https vs http


          2. SSL是什么?

          安全套接字層(SSL)是一種安全協(xié)議,為互聯(lián)網(wǎng)上傳輸?shù)臄?shù)據(jù)提供加密,并對(duì)網(wǎng)絡(luò)服務(wù)器進(jìn)行身份驗(yàn)證。當(dāng)您提交任何敏感資料時(shí),SSL會(huì)對(duì)您的數(shù)據(jù)進(jìn)行加密,以確保數(shù)據(jù)得到充分保護(hù)和安全,并且只有預(yù)期的收件人才能理解。SSL證書是由證書頒發(fā)機(jī)構(gòu)頒發(fā)給網(wǎng)站的數(shù)字證書,它保證了用戶的web瀏覽器和web服務(wù)器之間的所有信息都是加密的。因此,SSL證書保護(hù)您的數(shù)據(jù)免受惡意竊取或破壞,如竊聽、中間人攻擊等。

          一旦安裝SSL證書,網(wǎng)站協(xié)議將從HTTP轉(zhuǎn)移到安全的HTTPS。此外,您可以從瀏覽器中看到一個(gè)信任的標(biāo)識(shí),一個(gè)掛鎖,被添加到您的網(wǎng)站的URL中。如上圖所示。這可以確保訪問者使用安全連接進(jìn)行通信。SSL證書增加了網(wǎng)站的用戶體驗(yàn),并幫助提高其在谷歌搜索引擎結(jié)果頁面上的排名。它還可以驗(yàn)證網(wǎng)站的真實(shí)性。但是你怎么檢查這些信息呢?

          ssl原理


          3. 如何訪問SSL證書包含的信息?

          在瀏覽器上單擊地址欄中網(wǎng)址前面的掛鎖,可以查看SSL證書信息。它還包含關(guān)于網(wǎng)站身份的信息。以下是SSL證書的主要內(nèi)容:

          • 為其頒發(fā)證書的“域名”
          • 頒發(fā)證書的組織、人員或機(jī)構(gòu)
          • 頒發(fā)證書的證書頒發(fā)機(jī)構(gòu)的名稱
          • 簽發(fā)CA的數(shù)字簽名
          • 與之關(guān)聯(lián)的子域
          • 證書簽發(fā)日期
          • 證書的有效期

          web瀏覽器與web服務(wù)器通信,并使用該數(shù)據(jù)文件驗(yàn)證網(wǎng)站的身份和SSL證書的狀態(tài)。

          4. SSL證書如何保護(hù)用戶數(shù)據(jù)和隱私?

          SSL證書安裝在您的web服務(wù)器上后,它會(huì)以公鑰和私鑰的形式提供一個(gè)可識(shí)別的數(shù)字識(shí)別號(hào)碼,用于服務(wù)器的認(rèn)證。這些只不過是一長串任意生成的數(shù)字。它還允許服務(wù)器對(duì)用戶和服務(wù)器之間交換的敏感信息進(jìn)行加密和解密。

          • 當(dāng)一個(gè)訪問者訪問您的網(wǎng)站時(shí),用戶web瀏覽器將嘗試驗(yàn)證您網(wǎng)站的SSL證書的有效性,以及通過一個(gè)稱為握手的過程驗(yàn)證您的服務(wù)器。
          • 然后,web服務(wù)器發(fā)送其SSL證書的副本以及服務(wù)器的公鑰。
          • 瀏覽器根據(jù)受信任的ca列表、其到期日期和其真實(shí)性檢查SSL證書。
          • 一旦瀏覽器確信SSL證書是有效的,并且您的服務(wù)器已經(jīng)過身份驗(yàn)證,它將此指示給web服務(wù)器。
          • 此后,一個(gè)數(shù)字簽名的確認(rèn)被發(fā)送回瀏覽器,以建立一個(gè)安全的加密路徑,用于在web服務(wù)器和用戶之間的信息傳輸。
          • 如果瀏覽器發(fā)現(xiàn)您的SSL證書無效,則會(huì)向用戶顯示一個(gè)錯(cuò)誤信息“您的連接不是可信的”,這將導(dǎo)致您的訪問者立即離開您的網(wǎng)站。

          根據(jù)您的安全需求和預(yù)算,您可以從Internet上許多著名的證書頒發(fā)機(jī)構(gòu)(CAs)提供的各種選擇中購買SSL證書。因此,即使你預(yù)算有限,也要確保你的網(wǎng)站安全,使用有效的、便宜的SSL證書來贏得用戶的信任,保護(hù)你的品牌聲譽(yù)。因此,我們要了解不同類型的SSL證書。

          SSL證書如何保護(hù)用戶數(shù)據(jù)和隱私


          5. SSL證書的類型

          各種驗(yàn)證級(jí)別

          SSL證書的類型



          證書頒發(fā)機(jī)構(gòu)(CA)根據(jù)不同的驗(yàn)證級(jí)別需求頒發(fā)各種SSL證書。因此,SSL證書可以根據(jù)這些不同的驗(yàn)證級(jí)別過程進(jìn)行分類,如下所示:

          5.1 域驗(yàn)證(DV) SSL證書

          DV SSL證書申請(qǐng)驗(yàn)證過程非常簡單,幾乎不需要復(fù)雜的申請(qǐng)流程。因此,在SSL市場上可用的所有其他類型中,它需要的時(shí)間最短。DV SSL證書廣泛用于非金融交易或用戶敏感數(shù)據(jù)的小型網(wǎng)站。它們是最便宜的選擇,也被廣泛用于保護(hù)博客。它只能提供基礎(chǔ)的認(rèn)證。

          5.2 組織驗(yàn)證(OV) SSL證書

          CA需要進(jìn)行域驗(yàn)證,并驗(yàn)證所有者公司的真實(shí)性后,才能簽發(fā)OV SSL證書。OV SSL證書顯示公司的身份信息,可通過訪問證書上的信息查看。該公司的詳細(xì)信息顯示在“主題標(biāo)簽”中,如下面的例子所示:

          ssl certification


          中型企業(yè)比較普遍使用OV SSL證書,其發(fā)放時(shí)間比DV SSL證書長。由于證書所有者公司的驗(yàn)證過程需要更多的時(shí)間,所以比DV SSL證書的費(fèi)用更高。

          5.3 擴(kuò)展驗(yàn)證(EV) SSL證書

          EV SSL證書與最高程度的信任和聲譽(yù)相關(guān)聯(lián)。EV SSL證書必須經(jīng)過以下嚴(yán)格的認(rèn)證后才能簽發(fā)給組織。非常嚴(yán)格和徹底的背景驗(yàn)證是簽發(fā)驗(yàn)證程序的一部分,如其地址、目前的運(yùn)營狀況、法律狀況等。因此,與DV和OV SSL證書相比,此SSL證書的簽發(fā)時(shí)間最長,成本也更高。該公司的名稱顯示在地址欄,因此可以驗(yàn)證。可信任的標(biāo)識(shí),網(wǎng)站Logo在網(wǎng)站上的展示增加了用戶的信任。EV SSL證書廣泛應(yīng)用于銀行、大型金融機(jī)構(gòu)、電子商務(wù)網(wǎng)站等。

          6. 不同數(shù)量的域/子域

          使用不同類型SSL證書確保網(wǎng)站安全的另一個(gè)決定因素是需要保護(hù)的域和子域的數(shù)量,它們?nèi)缦?

          6.1 單域證書

          單域SSL證書為您的網(wǎng)站保護(hù)一個(gè)域或子域。

          為了保護(hù)多個(gè)域和子域,購買具有成本效益的通配符SSL證書或多域證書提供了更好的投資回報(bào)和更好的時(shí)間管理,而不是為每個(gè)域和子域使用單一域證書。

          6.2 通配符SSL證書

          通配符SSL證書僅使用一個(gè)證書就可以保護(hù)主域和其所有子域。通配符證書使用格式為*.example.com的通用名稱,因此它將使用單個(gè)證書來保護(hù)多個(gè)子域。如果考慮到預(yù)算問題,建議購買并安裝通配符SSL證書,該證書將提供與較昂貴證書相同的加密級(jí)別。

          6.3 多域/SAN SSL證書

          多域或SAN(主題可選名稱)SSL證書僅使用一個(gè)證書就可以保護(hù)多個(gè)域/子域。您可以添加和修改Subject Alternative Name字段,并輕松保護(hù)不同域和子域之間的多個(gè)名稱。例如,只需一個(gè)多域(SAN) SSL證書。

          6.4 統(tǒng)一通信證書(UCC)

          統(tǒng)一通信證書(UCC)只不過是多域SSL證書,早期設(shè)計(jì)用于保護(hù)Microsoft Exchange和Live Communications服務(wù)器。現(xiàn)在,它被用來保護(hù)任何多個(gè)域名,只需一個(gè)證書。UCC證書具有組織驗(yàn)證功能,還可以用作EV SSL證書,為用戶提供最高程度的信任和安全性。

          7. 結(jié)論

          總之,我們可以說,要贏得用戶的信任,并將你的在線業(yè)務(wù)或博客帶到新的成功高度,關(guān)注用戶數(shù)據(jù)的安全是至關(guān)重要的。要做到這一點(diǎn),沒有比使用廉價(jià)的SSL來保護(hù)你的網(wǎng)站或博客更好的方法了,它可以幫助你瞄準(zhǔn)你的安全需求和預(yù)算。


          如果喜歡本文,歡迎轉(zhuǎn)發(fā)。本文已同步至博客站,尊重原創(chuàng),轉(zhuǎn)載時(shí)請(qǐng)?jiān)谡闹懈綆б韵骆溄樱篽ttps://www.linuxrumen.com/rmxx/1994.html

          在這里我就不再一一介紹每個(gè)步驟的具體操作了,因?yàn)樵谂廊±习鏀?shù)據(jù)的時(shí)候都已經(jīng)講得非常清楚了,所以在這里我只會(huì)在重點(diǎn)上講述這個(gè)是這么實(shí)現(xiàn)的,如果想要看具體步驟請(qǐng)先去看我的文章內(nèi)容,里面有非常詳細(xì)的介紹以及是怎么找到加密js代碼和api接口。

          私信小編01即可獲取大量Python學(xué)習(xí)資料


          58同城網(wǎng)站分析

          58同城的數(shù)據(jù)爬取非常簡單,唯一有點(diǎn)難的就是字體的加密,除此之外其他的數(shù)據(jù)用xpath即可獲取。

          想爬取不同地方的直接訪問鏈接即可:


          數(shù)據(jù)在鏈接中,直接請(qǐng)求獲取即可。


          字體加密破解

          既然是字體加密那么就先把字體尋找出來,尋找簡單,在開發(fā)者工具中的分類找到Font,然后搜索這個(gè)鏈接進(jìn)行查找。


          已經(jīng)找到這個(gè)字體了,他是在請(qǐng)求頁面的時(shí)候返回的,然后他還是個(gè)base64的,只需要轉(zhuǎn)換一下再保存就可以了。

          請(qǐng)求鏈接獲取字體

          import requests
          from lxml import etree
          
          def get_data():
              url="https://bj.58.com/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1"
              headers={
                  'authority': 'bj.58.com',
                  'method': 'GET',
                  'path': '/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1',
                  'scheme': 'https',
                  'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                  'accept-encoding': 'gzip, deflate, br',
                  'accept-language': 'zh-CN,zh;q=0.9',
                  'cache-control': 'max-age=0',
                  'cookie': 'f=n; commontopbar_new_city_info=1%7C%E5%8C%97%E4%BA%AC%7Cbj; commontopbar_ipcity=bj%7C%E5%8C%97%E4%BA%AC%7C0; userid360_xml=C0E9739B2022549506AFBC01231A1DAA; time_create=1606640420140; xxzl_cid=f4a781439d9247f393d0a1629bec00df; xzuid=e0e5ea78-ac5a-491b-819d-a869ab37a7a7; xxzl_deviceid=2G3xFS3qwOviMHxtC%2FVEituhpmiI%2FJ%2BAmJ08cPBulZSe7LcSgT98WgFcyNDbzMXJ; id58=c5/nfF+bz1xVS0tAA7tjAg==; 58tj_uuid=116f1ed0-7c25-477e-8887-be3602fa2389; new_uv=1; utm_source=; spm=; init_refer=https%253A%252F%252Fbj.58.com%252Fchuzu%252Fsub%252Fpn70%252F%253Fpagetype%253Dditie%2526PGTID%253D0d3090a7-0000-1b87-3e2e-c6efe8d19973%2526ClickID%253D2; wmda_uuid=13712f08f0e555f110b1b2684ce9d709; wmda_new_uuid=1; wmda_session_id_11187958619315=1604046685879-d3ad7e5f-77f6-29d7; wmda_visited_projects=%3B11187958619315; als=0; f=n; new_session=0',
                  'sec-fetch-dest': 'document',
                  'sec-fetch-mode': 'navigate',
                  'sec-fetch-site': 'none',
                  'sec-fetch-user': '?1',
                  'upgrade-insecure-requests': '1',
                  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
              }
              response=requests.get(url=url, headers=headers)
              return response.text
          
          def get_font(data):
              html=etree.HTML(data)
              script=html.xpath('//script[2]/text()')[0]
              ttf=re.findall(".*?src:url\(\'data:application/font-ttf;charset=utf-8;base64,(.*?)\'\).*?",script,re.S)[0]
              with open('fangchan-secret.ttf','wb') as f:
                  f.write(base64.b64decode(ttf))
          
          if __name__=='__main__':
              data=get_data()
              get_font(data)

          解析字體字符

          import base64
          from fontTools.ttLib import TTFont
          import re
          import requests
          from lxml import etree
          
          def get_data():
              url="https://bj.58.com/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1"
              headers={
                  'authority': 'bj.58.com',
                  'method': 'GET',
                  'path': '/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1',
                  'scheme': 'https',
                  'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                  'accept-encoding': 'gzip, deflate, br',
                  'accept-language': 'zh-CN,zh;q=0.9',
                  'cache-control': 'max-age=0',
                  'cookie': 'f=n; commontopbar_new_city_info=1%7C%E5%8C%97%E4%BA%AC%7Cbj; commontopbar_ipcity=bj%7C%E5%8C%97%E4%BA%AC%7C0; userid360_xml=C0E9739B2022549506AFBC01231A1DAA; time_create=1606640420140; xxzl_cid=f4a781439d9247f393d0a1629bec00df; xzuid=e0e5ea78-ac5a-491b-819d-a869ab37a7a7; xxzl_deviceid=2G3xFS3qwOviMHxtC%2FVEituhpmiI%2FJ%2BAmJ08cPBulZSe7LcSgT98WgFcyNDbzMXJ; id58=c5/nfF+bz1xVS0tAA7tjAg==; 58tj_uuid=116f1ed0-7c25-477e-8887-be3602fa2389; new_uv=1; utm_source=; spm=; init_refer=https%253A%252F%252Fbj.58.com%252Fchuzu%252Fsub%252Fpn70%252F%253Fpagetype%253Dditie%2526PGTID%253D0d3090a7-0000-1b87-3e2e-c6efe8d19973%2526ClickID%253D2; wmda_uuid=13712f08f0e555f110b1b2684ce9d709; wmda_new_uuid=1; wmda_session_id_11187958619315=1604046685879-d3ad7e5f-77f6-29d7; wmda_visited_projects=%3B11187958619315; als=0; f=n; new_session=0',
                  'sec-fetch-dest': 'document',
                  'sec-fetch-mode': 'navigate',
                  'sec-fetch-site': 'none',
                  'sec-fetch-user': '?1',
                  'upgrade-insecure-requests': '1',
                  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
              }
              response=requests.get(url=url, headers=headers)
              return response.text
          
          def get_font(data):
              html=etree.HTML(data)
              script=html.xpath('//script[2]/text()')[0]
              ttf=re.findall(".*?src:url\(\'data:application/font-ttf;charset=utf-8;base64,(.*?)\'\).*?",script,re.S)[0]
              with open('fangchan-secret.ttf','wb') as f:
                  f.write(base64.b64decode(ttf))
          
          def parse_font():
              font=TTFont('fangchan-secret.ttf')
              bestcmap=font['cmap'].getBestCmap()
              newmap=dict()
              for key in bestcmap.keys():
                  value=int(re.search(r'(\d+)', bestcmap[key]).group(1)) - 1
                  key=hex(key)
                  newmap[key]=value
              print(newmap)
          
          if __name__=='__main__':
              data=get_data()
              get_font(data)
              parse_font()


          我們發(fā)現(xiàn)字體編號(hào)和之前的不符合,比如:
          0x9476=7,而這里的是2,這是什么原因呢?是因?yàn)樗淖煮w是動(dòng)態(tài)生成的,每次返回的數(shù)字編號(hào)對(duì)應(yīng)的值都是不同的,但是不影響我們代碼的正常運(yùn)行與結(jié)果。

          import base64
          from fontTools.ttLib import TTFont
          import re
          import requests
          from lxml import etree
          
          def get_data():
              url="https://bj.58.com/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1"
              headers={
                  'authority': 'bj.58.com',
                  'method': 'GET',
                  'path': '/chuzu/?PGTID=0d200001-0000-11e9-58e6-a658f219b27c&ClickID=1',
                  'scheme': 'https',
                  'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                  'accept-encoding': 'gzip, deflate, br',
                  'accept-language': 'zh-CN,zh;q=0.9',
                  'cache-control': 'max-age=0',
                  'cookie': 'f=n; commontopbar_new_city_info=1%7C%E5%8C%97%E4%BA%AC%7Cbj; commontopbar_ipcity=bj%7C%E5%8C%97%E4%BA%AC%7C0; userid360_xml=C0E9739B2022549506AFBC01231A1DAA; time_create=1606640420140; xxzl_cid=f4a781439d9247f393d0a1629bec00df; xzuid=e0e5ea78-ac5a-491b-819d-a869ab37a7a7; xxzl_deviceid=2G3xFS3qwOviMHxtC%2FVEituhpmiI%2FJ%2BAmJ08cPBulZSe7LcSgT98WgFcyNDbzMXJ; id58=c5/nfF+bz1xVS0tAA7tjAg==; 58tj_uuid=116f1ed0-7c25-477e-8887-be3602fa2389; new_uv=1; utm_source=; spm=; init_refer=https%253A%252F%252Fbj.58.com%252Fchuzu%252Fsub%252Fpn70%252F%253Fpagetype%253Dditie%2526PGTID%253D0d3090a7-0000-1b87-3e2e-c6efe8d19973%2526ClickID%253D2; wmda_uuid=13712f08f0e555f110b1b2684ce9d709; wmda_new_uuid=1; wmda_session_id_11187958619315=1604046685879-d3ad7e5f-77f6-29d7; wmda_visited_projects=%3B11187958619315; als=0; f=n; new_session=0',
                  'sec-fetch-dest': 'document',
                  'sec-fetch-mode': 'navigate',
                  'sec-fetch-site': 'none',
                  'sec-fetch-user': '?1',
                  'upgrade-insecure-requests': '1',
                  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
              }
              response=requests.get(url=url, headers=headers)
              return response.text
          
          def get_font(data):
              html=etree.HTML(data)
              script=html.xpath('//script[2]/text()')[0]
              ttf=re.findall(".*?src:url\(\'data:application/font-ttf;charset=utf-8;base64,(.*?)\'\).*?",script,re.S)[0]
              with open('fangchan-secret.ttf','wb') as f:
                  f.write(base64.b64decode(ttf))
          
          def parse_font():
              font=TTFont('fangchan-secret.ttf')
              bestcmap=font['cmap'].getBestCmap()
              newmap=dict()
              for key in bestcmap.keys():
                  value=int(re.search(r'(\d+)', bestcmap[key]).group(1)) - 1
                  key=hex(key)
                  newmap[key]=value
              return newmap
          
          def parse_data(data,newmap):
              for key,value in newmap.items():
                  key_=key.replace('0x','&#x') + ';'
                  if key_ in data:
                      data=data.replace(key_,str(value))
              html=etree.HTML(data)
              house_list=html.xpath('//ul[@class="house-list"]/li')[:-1]
              for house in house_list:
                  room=house.xpath('.//p[@class="room"]/text()')[0]
                  money=house.xpath('.//b[@class="strongbox"]/text()')[0]
                  print(room,money)
          
          if __name__=='__main__':
              data=get_data()
              get_font(data)
              newmap=parse_font()
              parse_data(data,newmap)

          聲明:本文僅供學(xué)習(xí)交流使用,請(qǐng)勿用于商業(yè)用途,違者后果自負(fù)。


          主站蜘蛛池模板: 国产一区二区在线观看麻豆| 欧美激情一区二区三区成人| 亚洲国产精品一区| 另类国产精品一区二区| 99久久精品国产高清一区二区| 亚无码乱人伦一区二区| 国产在线无码视频一区二区三区| 久久中文字幕无码一区二区 | 无码日韩精品一区二区三区免费| 国产婷婷色一区二区三区深爱网| 精品欧洲av无码一区二区| 亚洲熟妇av一区二区三区漫画| 日韩一区二区三区在线观看 | 久久久精品人妻一区二区三区蜜桃| 亚洲视频在线一区二区| 国产在线精品一区在线观看| 性盈盈影院免费视频观看在线一区| 中文字幕一区二区三区5566| 久久免费区一区二区三波多野| 一区五十路在线中出| 国产精品福利一区| 国产产一区二区三区久久毛片国语| 午夜福利无码一区二区| 久久精品无码一区二区三区不卡| 国产经典一区二区三区蜜芽| 2021国产精品一区二区在线| 久久国产精品一区免费下载| 无码少妇精品一区二区免费动态| 日韩人妻一区二区三区蜜桃视频| 久久精品国产一区二区三 | 日本一区二区三区精品视频| 精品人妻少妇一区二区三区不卡| 国产欧美色一区二区三区| 精品人妻无码一区二区色欲产成人| 日韩中文字幕一区| 国产精品一区二区毛卡片| 精品一区二区三区免费毛片| 一区二区国产在线播放| 亚洲中文字幕无码一区| 文中字幕一区二区三区视频播放| 乱精品一区字幕二区|