精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

大前端時代安全性如何做

安全 應用安全
我覺得對于國內的大數據公司沒幾家是有真正的大數據量,而是通過爬蟲工程師團隊不斷的去各地爬取數據,因此不要以為我們的數據沒價值,對于內容型的公司來說,數據是可信競爭力。那么我接下來想說的就是網絡和數據的安全性問題。

之前在上家公司的時候做過一些爬蟲的工作,也幫助爬蟲工程師解決過一些問題。然后我寫過一些文章發布到網上,之后有一些人就找我做一些爬蟲的外包,內容大概是爬取小紅書的用戶數據和商品數據,但是我沒做。我覺得對于國內的大數據公司沒幾家是有真正的大數據量,而是通過爬蟲工程師團隊不斷的去各地爬取數據,因此不要以為我們的數據沒價值,對于內容型的公司來說,數據是可信競爭力。那么我接下來想說的就是網絡和數據的安全性問題。

[[255777]]

對于內容型的公司,數據的安全性很重要。對于內容公司來說,數據的重要性不言而喻。比如你一個做在線教育的平臺,題目的數據很重要吧,但是被別人通過爬蟲技術全部爬走了?如果核心競爭力都被拿走了,那就是涼涼。再比說有個獨立開發者想抄襲你的產品,通過抓包和爬蟲手段將你核心的數據拿走,然后短期內做個網站和 App,短期內成為你的勁敵。

背景

目前通過 App 中的 網頁分析后,我們的數據安全性做的較差,有以下幾個點存在問題:

網站的數據通過最早期的前后端分離來實現。稍微學過 Web 前端的工程師都可以通過神器 Chrome 分析網站,進而爬取需要的數據。打開 「Network」就可以看到網站的所有網絡請求了,哎呀,不小心我看到了什么?沒錯就是網站的接口信息都可以看到了。比如 “detail.json?itemId=141529859”。或者你的網站接口有些特殊的判斷處理,將一些信息存儲到 sessionStorage、cookie、localStorage 里面,有點前端經驗的爬蟲工程師心想”嘿嘿嘿,這不是在裸奔數據么“?;蛘哂行﹨凳峭ㄟ^ JavaScript 臨時通過函數生成的。問題不大,工程師也可以對網頁元素進行查找,找到關鍵的 id、或者 css 類名,然后在 "Search“ 可以進行查找,找到對應的代碼 JS 代碼,點擊查看代碼,如果是早期前端開發模式那么代碼就是裸奔的,跟開發者在自己的 IDE 里面看到的內容一樣,有經驗的爬蟲就可以拿這個做事情,因此安全性問題亟待解決。

 

 

App 的數據即使采用了 HTTPS,但是對于專業的抓包工具也是可以直接拿到數據的,因此 App 的安全問題也可以做一些提高,具體的策略下文會講到。

爬蟲手段

  • 目前爬蟲技術都是從渲染好的 html 頁面直接找到感興趣的節點,然后獲取對應的文本
  • 有些網站安全性做的好,比如列表頁可能好獲取,但是詳情頁就需要從列表頁點擊對應的 item,將 itemId 通過 form 表單提交,服務端生成對應的參數,然后重定向到詳情頁(重定向過來的地址后才帶有詳情頁的參數 detailID),這個步驟就可以攔截掉一部分的爬蟲開發者

解決方案

制定出Web 端反爬技術方案

本人從這2個角度(網頁所見非所得、查接口請求沒用)出發,制定了下面的反爬方案。

  • 使用HTTPS 協議
  • 單位時間內限制掉請求次數過多,則封鎖該賬號
  • 前端技術限制 (接下來是核心技術)
  1. # 比如需要正確顯示的數據為“19950220” 
  2.  
  3. 1. 先按照自己需求利用相應的規則(數字亂序映射,比如正常的0對應還是0,但是亂序就是 0 <-> 1,1 <-> 9,3 <-> 8,...)制作自定義字體(ttf) 
  4. 2. 根據上面的亂序映射規律,求得到需要返回的數據 19950220 -> 17730220 
  5. 3. 對于第一步得到的字符串,依次遍歷每個字符,將每個字符根據按照線性變換(y=kx+b)。線性方程的系數和常數項是根據當前的日期計算得到的。比如當前的日期為“2018-07-24”,那么線性變換的 k 為 7,b 為 24。 
  6. 4. 然后將變換后的每個字符串用“3.1415926”拼接返回給接口調用者。(為什么是3.1415926,因為對數字偽造反爬,所以拼接的文本肯定是數字的話不太會引起研究者的注意,但是數字長度太短會誤傷正常的數據,所以用所熟悉的 Π) 
  7.  
  8. ​``` 
  9. 1773 -> “1*7+24” + “3.1415926” + “7*7+24” + “3.1415926” + “7*7+24” + “3.1415926” + “3*7+24” -> 313.1415926733.1415926733.141592645 
  10. 02 -> "0*7+24" + "3.1415926" + "2*7+24" -> 243.141592638 
  11. 20 -> "2*7+24" + "3.1415926" + "0*7+24" -> 383.141592624 
  12. ​``` 
  13.  
  14. # 前端拿到數據后再解密,解密后根據自定義的字體 Render 頁面 
  15. 1. 先將拿到的字符串按照“3.1415926”拆分為數組 
  16. 2. 對數組的每1個數據,按照“線性變換”(y=kx+b,k和b同樣按照當前的日期求解得到),逆向求解到原本的值。 
  17. 3. 將步驟2的的到的數據依次拼接,再根據 ttf 文件 Render 頁面上。 
  • 后端需要根據上一步設計的協議將數據進行加密處理

下面以 Node.js 為例講解后端需要做的事情

  • 首先后端設置接口路由
  • 獲取路由后面的參數
  • 根據業務需要根據 SQL 語句生成對應的數據。如果是數字部分,則需要按照上面約定的方法加以轉換。
  • 將生成數據轉換成 JSON 返回給調用者
  1. // json 
  2. var JoinOparatorSymbol = "3.1415926"
  3. function encode(rawData, ruleType) { 
  4.   if (!isNotEmptyStr(rawData)) { 
  5.     return ""
  6.   } 
  7.   var date = new Date(); 
  8.   var year = date.getFullYear(); 
  9.   var month = date.getMonth() + 1; 
  10.   var day = date.getDate(); 
  11.  
  12.   var encodeData = ""
  13.   for (var index = 0; index < rawData.length; index++) { 
  14.     var datacomponent = rawData[index]; 
  15.     if (!isNaN(datacomponent)) { 
  16.       if (ruleType < 3) { 
  17.         var currentNumber = rawDataMap(String(datacomponent), ruleType); 
  18.         encodeData += (currentNumber * month + day) + JoinOparatorSymbol; 
  19.       } 
  20.       else if (ruleType == 4) { 
  21.         encodeData += rawDataMap(String(datacomponent), ruleType); 
  22.       } 
  23.       else { 
  24.         encodeData += rawDataMap(String(datacomponent), ruleType) + JoinOparatorSymbol; 
  25.       } 
  26.     } 
  27.     else if (ruleType == 4) { 
  28.       encodeData += rawDataMap(String(datacomponent), ruleType); 
  29.     } 
  30.  
  31.   } 
  32.   if (encodeData.length >= JoinOparatorSymbol.length) { 
  33.     var lastTwoString = encodeData.substring(encodeData.length - JoinOparatorSymbol.length, encodeData.length); 
  34.     if (lastTwoString == JoinOparatorSymbol) { 
  35.       encodeData = encodeData.substring(0, encodeData.length - JoinOparatorSymbol.length); 
  36.     } 
  37.   } 
  1. //字體映射處理 
  2. function rawDataMap(rawData, ruleType) { 
  3.  
  4.   if (!isNotEmptyStr(rawData) || !isNotEmptyStr(ruleType)) { 
  5.     return
  6.   } 
  7.   var mapData; 
  8.   var rawNumber = parseInt(rawData); 
  9.   var ruleTypeNumber = parseInt(ruleType); 
  10.   if (!isNaN(rawData)) { 
  11.     lastNumberCategory = ruleTypeNumber; 
  12.     //字體文件1下的數據加密規則 
  13.     if (ruleTypeNumber == 1) { 
  14.       if (rawNumber == 1) { 
  15.         mapData = 1; 
  16.       } 
  17.       else if (rawNumber == 2) { 
  18.         mapData = 2; 
  19.       } 
  20.       else if (rawNumber == 3) { 
  21.         mapData = 4; 
  22.       } 
  23.       else if (rawNumber == 4) { 
  24.         mapData = 5; 
  25.       } 
  26.       else if (rawNumber == 5) { 
  27.         mapData = 3; 
  28.       } 
  29.       else if (rawNumber == 6) { 
  30.         mapData = 8; 
  31.       } 
  32.       else if (rawNumber == 7) { 
  33.         mapData = 6; 
  34.       } 
  35.       else if (rawNumber == 8) { 
  36.         mapData = 9; 
  37.       } 
  38.       else if (rawNumber == 9) { 
  39.         mapData = 7; 
  40.       } 
  41.       else if (rawNumber == 0) { 
  42.         mapData = 0; 
  43.       } 
  44.     } 
  45.     //字體文件2下的數據加密規則 
  46.     else if (ruleTypeNumber == 0) { 
  47.  
  48.       if (rawNumber == 1) { 
  49.         mapData = 4; 
  50.       } 
  51.       else if (rawNumber == 2) { 
  52.         mapData = 2; 
  53.       } 
  54.       else if (rawNumber == 3) { 
  55.         mapData = 3; 
  56.       } 
  57.       else if (rawNumber == 4) { 
  58.         mapData = 1; 
  59.       } 
  60.       else if (rawNumber == 5) { 
  61.         mapData = 8; 
  62.       } 
  63.       else if (rawNumber == 6) { 
  64.         mapData = 5; 
  65.       } 
  66.       else if (rawNumber == 7) { 
  67.         mapData = 6; 
  68.       } 
  69.       else if (rawNumber == 8) { 
  70.         mapData = 7; 
  71.       } 
  72.       else if (rawNumber == 9) { 
  73.         mapData = 9; 
  74.       } 
  75.       else if (rawNumber == 0) { 
  76.         mapData = 0; 
  77.       } 
  78.     } 
  79.     //字體文件3下的數據加密規則 
  80.     else if (ruleTypeNumber == 2) { 
  81.  
  82.       if (rawNumber == 1) { 
  83.         mapData = 6; 
  84.       } 
  85.       else if (rawNumber == 2) { 
  86.         mapData = 2; 
  87.       } 
  88.       else if (rawNumber == 3) { 
  89.         mapData = 1; 
  90.       } 
  91.       else if (rawNumber == 4) { 
  92.         mapData = 3; 
  93.       } 
  94.       else if (rawNumber == 5) { 
  95.         mapData = 4; 
  96.       } 
  97.       else if (rawNumber == 6) { 
  98.         mapData = 8; 
  99.       } 
  100.       else if (rawNumber == 7) { 
  101.         mapData = 3; 
  102.       } 
  103.       else if (rawNumber == 8) { 
  104.         mapData = 7; 
  105.       } 
  106.       else if (rawNumber == 9) { 
  107.         mapData = 9; 
  108.       } 
  109.       else if (rawNumber == 0) { 
  110.         mapData = 0; 
  111.       } 
  112.     } 
  113.     else if (ruleTypeNumber == 3) { 
  114.  
  115.       if (rawNumber == 1) { 
  116.         mapData = "&#xefab;"
  117.       } 
  118.       else if (rawNumber == 2) { 
  119.         mapData = "&#xeba3;"
  120.       } 
  121.       else if (rawNumber == 3) { 
  122.         mapData = "&#xecfa;"
  123.       } 
  124.       else if (rawNumber == 4) { 
  125.         mapData = "&#xedfd;"
  126.       } 
  127.       else if (rawNumber == 5) { 
  128.         mapData = "&#xeffa;"
  129.       } 
  130.       else if (rawNumber == 6) { 
  131.         mapData = "&#xef3a;"
  132.       } 
  133.       else if (rawNumber == 7) { 
  134.         mapData = "&#xe6f5;"
  135.       } 
  136.       else if (rawNumber == 8) { 
  137.         mapData = "&#xecb2;"
  138.       } 
  139.       else if (rawNumber == 9) { 
  140.         mapData = "&#xe8ae;"
  141.       } 
  142.       else if (rawNumber == 0) { 
  143.         mapData = "&#xe1f2;"
  144.       } 
  145.     } 
  146.     else
  147.       mapData = rawNumber; 
  148.     } 
  149.   } else if (ruleTypeNumber == 4) { 
  150.     var sources = ["年""萬""業""人""信""元""千""司""州""資""造""錢"]; 
  151.     //判斷字符串為漢字 
  152.     if (/^[\u4e00-\u9fa5]*$/.test(rawData)) { 
  153.  
  154.       if (sources.indexOf(rawData) > -1) { 
  155.         var currentChineseHexcod = rawData.charCodeAt(0).toString(16); 
  156.         var lastCompoent; 
  157.         var mapComponetnt; 
  158.         var numbers = ["0""1""2""3""4""5""6""7""8""9"]; 
  159.         var characters = ["a""b""c""d""e""f""g""h""h""i""j""k""l""m""n""o""p""q""r""s""t""u""v""w""x""y""z"]; 
  160.  
  161.         if (currentChineseHexcod.length == 4) { 
  162.           lastCompoent = currentChineseHexcod.substr(3, 1); 
  163.           var locationInComponents = 0; 
  164.           if (/[0-9]/.test(lastCompoent)) { 
  165.             locationInComponents = numbers.indexOf(lastCompoent); 
  166.             mapComponetnt = numbers[(locationInComponents + 1) % 10]; 
  167.           } 
  168.           else if (/[a-z]/.test(lastCompoent)) { 
  169.             locationInComponents = characters.indexOf(lastCompoent); 
  170.             mapComponetnt = characters[(locationInComponents + 1) % 26]; 
  171.           } 
  172.           mapData = "&#x" + currentChineseHexcod.substr(0, 3) + mapComponetnt + ";"
  173.         } 
  174.       } else { 
  175.         mapData = rawData; 
  176.       } 
  177.  
  178.     } 
  179.     else if (/[0-9]/.test(rawData)) { 
  180.       mapData = rawDataMap(rawData, 2); 
  181.     } 
  182.     else { 
  183.       mapData = rawData; 
  184.     } 
  185.  
  186.   } 
  187.   return mapData; 
  1. //api 
  2. module.exports = { 
  3.     "GET /api/products": async (ctx, next) => { 
  4.         ctx.response.type = "application/json"
  5.         ctx.response.body = { 
  6.             products: products 
  7.         }; 
  8.     }, 
  9.  
  10.     "GET /api/solution1": async (ctx, next) => { 
  11.  
  12.         try { 
  13.             var data = fs.readFileSync(pathname, "utf-8"); 
  14.             ruleJson = JSON.parse(data); 
  15.             rule = ruleJson.data.rule
  16.         } catch (error) { 
  17.             console.log("fail: " + error); 
  18.         } 
  19.  
  20.         var data = { 
  21.             code: 200, 
  22.             message: "success"
  23.             data: { 
  24.                 name"@杭城小劉"
  25.                 year: LBPEncode("1995"rule), 
  26.                 month: LBPEncode("02"rule), 
  27.                 day: LBPEncode("20"rule), 
  28.                 analysis : rule 
  29.             } 
  30.         } 
  31.  
  32.         ctx.set("Access-Control-Allow-Origin""*"); 
  33.         ctx.response.type = "application/json"
  34.         ctx.response.body = data; 
  35.     }, 
  36.  
  37.  
  38.     "GET /api/solution2": async (ctx, next) => { 
  39.         try { 
  40.             var data = fs.readFileSync(pathname, "utf-8"); 
  41.             ruleJson = JSON.parse(data); 
  42.             rule = ruleJson.data.rule
  43.         } catch (error) { 
  44.             console.log("fail: " + error); 
  45.         } 
  46.  
  47.         var data = { 
  48.             code: 200, 
  49.             message: "success"
  50.             data: { 
  51.                 name: LBPEncode("建造師",rule), 
  52.                 birthday: LBPEncode("1995年02月20日",rule), 
  53.                 company: LBPEncode("中天公司",rule), 
  54.                 address: LBPEncode("浙江省杭州市拱墅區石祥路",rule), 
  55.                 bidprice: LBPEncode("2萬元",rule), 
  56.                 negative: LBPEncode("2018年辦事效率太高、負面基本沒有",rule), 
  57.                 title: LBPEncode("建造師",rule), 
  58.                 honor: LBPEncode("最佳獎",rule), 
  59.                 analysis : rule 
  60.             } 
  61.         } 
  62.         ctx.set("Access-Control-Allow-Origin""*"); 
  63.         ctx.response.type = "application/json"
  64.         ctx.response.body = data; 
  65.     }, 
  66.  
  67.     "POST /api/products": async (ctx, next) => { 
  68.         var p = { 
  69.             name: ctx.request.body.name
  70.             price: ctx.request.body.price 
  71.         }; 
  72.         products.push(p); 
  73.         ctx.response.type = "application/json"
  74.         ctx.response.body = p; 
  75.     } 
  76. }; 
  1. //路由 
  2. const fs = require("fs"); 
  3.  
  4. function addMapping(router, mapping){ 
  5.     for(var url in mapping){ 
  6.         if (url.startsWith("GET")) { 
  7.             var path = url.substring(4); 
  8.             router.get(path,mapping[url]); 
  9.             console.log(`Register URL mapping: GET: ${path}`); 
  10.         }else if (url.startsWith('POST ')) { 
  11.             var path = url.substring(5); 
  12.             router.post(path, mapping[url]); 
  13.             console.log(`Register URL mapping: POST ${path}`); 
  14.         } else if (url.startsWith('PUT ')) { 
  15.             var path = url.substring(4); 
  16.             router.put(path, mapping[url]); 
  17.             console.log(`Register URL mapping: PUT ${path}`); 
  18.         } else if (url.startsWith('DELETE ')) { 
  19.             var path = url.substring(7); 
  20.             router.del(path, mapping[url]); 
  21.             console.log(`Register URL mapping: DELETE ${path}`); 
  22.         } else { 
  23.             console.log(`Invalid URL: ${url}`); 
  24.         } 
  25.  
  26.     } 
  27.  
  28.  
  29. function addControllers(router, dir){ 
  30.     fs.readdirSync(__dirname + "/" + dir).filter( (f) => { 
  31.         return f.endsWith(".js"); 
  32.     }).forEach( (f) => { 
  33.         console.log(`Process controllers:${f}...`); 
  34.         let mapping = require(__dirname + "/" + dir + "/" + f); 
  35.         addMapping(router,mapping); 
  36.     }); 
  37.  
  38. module.exports = function(dir){ 
  39.     let controllers = dir || "controller"
  40.     let router = require("koa-router")(); 
  41.  
  42.     addControllers(router,controllers); 
  43.     return router.routes(); 
  44. }; 
  • 前端根據服務端返回的數據逆向解密
  1. $("#year").html(getRawData(data.year,log)); 
  2.  
  3. // util.js 
  4. var JoinOparatorSymbol = "3.1415926"
  5. function isNotEmptyStr($str) { 
  6.   if (String($str) == "" || $str == undefined || $str == null || $str == "null") { 
  7.     return false
  8.   } 
  9.   return true
  10.  
  11. function getRawData($json,analisys) { 
  12.   $json = $json.toString(); 
  13.   if (!isNotEmptyStr($json)) { 
  14.     return
  15.   } 
  16.    
  17.   var date= new Date(); 
  18.   var year = date.getFullYear(); 
  19.   var month = date.getMonth() + 1; 
  20.   var day = date.getDate(); 
  21.   var datacomponents = $json.split(JoinOparatorSymbol); 
  22.   var orginalMessage = ""
  23.   for(var index = 0;index < datacomponents.length;index++){ 
  24.     var datacomponent = datacomponents[index]; 
  25.       if (!isNaN(datacomponent) && analisys < 3){ 
  26.           var currentNumber = parseInt(datacomponent); 
  27.           orginalMessage += (currentNumber -  day)/month
  28.       } 
  29.       else if(analisys == 3){ 
  30.          orginalMessage += datacomponent; 
  31.       } 
  32.       else
  33.         //其他情況待續,本 Demo 根據本人在研究反爬方面的技術并實踐后持續更新 
  34.       } 
  35.   } 
  36.   return orginalMessage; 

比如后端返回的是323.14743.14743.1446,根據我們約定的算法,可以的到結果為1773

  • 根據 ttf 文件 Render 頁面

 

上面計算的到的1773,然后根據ttf文件,頁面看到的就是1995

  • 然后為了防止爬蟲人員查看 JS 研究問題,所以對 JS 的文件進行了加密處理。如果你的技術棧是 Vue 、React 等,webpack 為你提供了 JS 加密的插件,也很方便處理

JS混淆工具

個人覺得這種方式還不是很安全。于是想到了各種方案的組合拳。比如

反爬升級版

個人覺得如果一個前端經驗豐富的爬蟲開發者來說,上面的方案可能還是會存在被破解的可能,所以在之前的基礎上做了升級版本

  • 組合拳1: 字體文件不要固定,雖然請求的鏈接是同一個,但是根據當前的時間戳的最后一個數字取模,比如 Demo 中對4取模,有4種值 0、1、2、3。這4種值對應不同的字體文件,所以當爬蟲絞盡腦汁爬到1種情況下的字體時,沒想到再次請求,字體文件的規則變掉了 😂
  • 組合拳2: 前面的規則是字體問題亂序,但是只是數字匹配打亂掉。比如 1 -> 4, 5 -> 8。接下來的套路就是每個數字對應一個 unicode 碼 ,然后制作自己需要的字體,可以是 .ttf、.woff 等等。

這幾種組合拳打下來。對于一般的爬蟲就放棄了。

反爬手段再升級

上面說的方法主要是針對數字做的反爬手段,如果要對漢字進行反爬怎么辦?接下來提供幾種方案

  • 方案1: 對于你站點頻率最高的詞云,做一個漢字映射,也就是自定義字體文件,步驟跟數字一樣。先將常用的漢字生成對應的 ttf 文件;根據下面提供的鏈接,將 ttf 文件轉換為 svg 文件,然后在下面的“字體映射”鏈接點進去的網站上面選擇前面生成的 svg 文件,將svg文件里面的每個漢字做個映射,也就是將漢字專為 unicode 碼(注意這里的 unicode 碼不要去在線直接生成,因為直接生成的東西也就是有規律的。我給的做法是先用網站生成,然后將得到的結果做個簡單的變化,比如將“e342”轉換為 “e231”);然后接口返回的數據按照我們的這個字體文件的規則反過去映射出來。
  • 方案2: 將網站的重要字體,將 html 部分生成圖片,這樣子爬蟲要識別到需要的內容成本就很高了,需要用到 OCR。效率也很低。所以可以攔截掉一部分的爬蟲
  • 方案3: 看到攜程的技術分享“反爬的最高境界就是 Canvas 的指紋,原理是不同的機器不同的硬件對于 Canvas 畫出的圖總是存在像素級別的誤差,因此我們判斷當對于訪問來說大量的 canvas 的指紋一致的話,則認為是爬蟲,則可以封掉它”。

本人將方案1實現到 Demo 中了。

關鍵步驟

  1. 先根據你們的產品找到常用的關鍵詞,生成詞云
  2. 根據詞云,將每個字生成對應的 unicode 碼
  3. 將詞云包括的漢字做成一個字體庫
  4. 將字體庫 .ttf 做成 svg 格式,然后上傳到 icomoon 制作自定義的字體,但是有規則,比如 “年” 對應的 unicode 碼是 “u5e74” ,但是我們需要做一個 愷撒加密 ,比如我們設置 偏移量 為1,那么經過愷撒加密 “年”對應的 unicode 碼是“u5e75” 。利用這種規則制作我們需要的字體庫
  5. 在每次調用接口的時候服務端做的事情是:服務端封裝某個方法,將數據經過方法判斷是不是在詞云中,如果是詞云中的字符,利用規則(找到漢字對應的 unicode 碼,再根據凱撒加密,設置對應的偏移量,Demo 中為1,將每個漢字加密處理)加密處理后返回數據
  6. 客戶端做的事情:
  • 先引入我們前面制作好的漢字字體庫
  • 調用接口拿到數據,顯示到對應的 Dom 節點上
  • 如果是漢字文本,我們將對應節點的 css 類設置成漢字類,該類對應的 font-family 是我們上面引入的漢字字體庫
  1. //style.css 
  2. @font-face { 
  3.   font-family: "NumberFont"
  4.   src: url('http://127.0.0.1:8080/Util/analysis'); 
  5.   -webkit-font-smoothing: antialiased; 
  6.   -moz-osx-font-smoothing: grayscale; 
  7.  
  8. @font-face { 
  9.   font-family: "CharacterFont"
  10.   src: url('http://127.0.0.1:8080/Util/map'); 
  11.   -webkit-font-smoothing: antialiased; 
  12.   -moz-osx-font-smoothing: grayscale; 
  13.  
  14. h2 { 
  15.   font-family: "NumberFont"
  16.  
  17. h3,a{ 
  18.   font-family: "CharacterFont"

 

 

傳送門

字體制作的步驟、ttf轉svg、字體映射規則

實現的效果

頁面上看到的數據跟審查元素看到的結果不一致

去查看接口數據跟審核元素和界面看到的三者不一致

頁面每次刷新之前得出的結果更不一致

對于數字和漢字的處理手段都不一致

這幾種組合拳打下來。對于一般的爬蟲就放棄了。

前面的 ttf 轉 svg 網站當 ttf 文件太大會限制轉換,讓你購買,下面貼出個新的鏈接。

ttf轉svg

Demo 地址

運行步驟

  1. //客戶端。先查看本機 ip 在 Demo/Spider-develop/Solution/Solution1.js 和 Demo/Spider-develop/Solution/Solution2.js  里面將接口地址修改為本機 ip 
  2.  
  3. $ cd Demo 
  4. $ ls 
  5. REST        Spider-release    file-Server.js 
  6. Spider-develop    Util        rule.json 
  7. $ node file-Server.js  
  8. Server is runnig at http://127.0.0.1:8080/ 
  9.  
  10. //服務端 先安裝依賴 
  11. $ cd REST/ 
  12. $ npm install 
  13. $ node app.js  

App 端安全的解決方案

  • 目前 App 的網絡通信基本都是用 HTTPS 的服務,但是隨便一個抓包工具都是可以看到 HTTPS 接口的詳細數據,為了做到防止抓包和無法模擬接口的情況,我們采取以下措施:
  1. 中間人盜用數據,我們可以采取 HTTPS 證書的雙向認證,這樣子實現的效果就是中間人在開啟抓包軟件分析 App 的網絡請求的時候,網絡會自動斷掉,無法查看分析請求的情況
  2. 對于防止用戶模仿我們的請求再次發起請求,我們可以采用 「防重放策略」,用戶再也無法模仿我們的請求,再次去獲取數據了。
  3. 對于 App 內的 H5 資源,反爬蟲方案可以采用上面的解決方案,H5 內部的網絡請求可以通過 Hybrid 層讓 Native 的能力去完成網絡請求,完成之后將數據回調給 JS。這么做的目的是往往我們的 Native 層有完善的賬號體系和網絡層以及良好的安全策略、鑒權體系等等。
  4. 后期會討論 App 安全性的更深層次玩法,比如從逆向的角度出發如何保護 App 的安全性。

關于 Hybrid 的更多內容,可以看看這篇文章 Awesome Hybrid

  • 比如 JS 需要發起一個網絡請求,那么按照上面將網絡請求讓 Native 去完成,然后回調給 JS
  1. var requestObject = { 
  2.   url: arg.Api + "SearchInfo/getLawsInfo"
  3.   params: requestparams, 
  4.   Hybrid_Request_Method: 0 
  5. }; 
  6. requestHybrid({ 
  7.   tagname: 'NativeRequest'
  8.   param: requestObject, 
  9.   encryption: 1, 
  10.   callback: function (data) { 
  11.     renderUI(data); 
  12.   } 
  13. }) 

Native 代碼(iOS為例)

  1. [self.bridge registerHandler:@"NativeRequest" handler:^(id data, WVJBResponseCallback responseCallback) { 
  2.        
  3.     NSAssert([data isKindOfClass:[NSDictionary class]], @"H5 端不按套路"); 
  4.     if ([data isKindOfClass:[NSDictionary class]]) { 
  5.          
  6.         NSDictionary *dict = (NSDictionary *)data; 
  7.         RequestModel *requestModel = [RequestModel yy_modelWithJSON:dict]; 
  8.         NSAssert( (requestModel.Hybrid_Request_Method == Hybrid_Request_Method_Post) || (requestModel.Hybrid_Request_Method == Hybrid_Request_Method_Get ), @"H5 端不按套路"); 
  9.          
  10.         [HybridRequest requestWithNative:requestModel hybridRequestSuccess:^(id responseObject) { 
  11.              
  12.             NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableLeaves error:nil]; 
  13.             responseCallback([self convertToJsonData:@{@"success":@"1",@"data":json}]); 
  14.              
  15.         } hybridRequestfail:^{ 
  16.              
  17.             LBPLog(@"H5 call Native`s request failed"); 
  18.             responseCallback([self convertToJsonData:@{@"success":@"0",@"data":@""}]); 
  19.         }]; 
  20.     } 
  21. }]; 

 

責任編輯:武曉燕 來源: segmentfault
相關推薦

2022-10-19 14:16:18

樣式隔離前綴css

2010-09-29 09:48:12

數據庫安全

2021-10-19 06:05:20

網站安全網絡威脅網絡攻擊

2022-10-10 13:22:38

物聯網安全隱私

2009-11-30 09:41:38

2017-06-12 08:47:14

ESXi安全vSphere

2021-02-26 20:07:54

安全性健壯性代碼

2022-03-03 12:53:40

云遷移云計算云平臺

2017-12-08 21:26:52

物聯網DDI安全性

2024-05-28 09:05:31

2020-03-06 10:36:21

JavaScriptCSSHTML

2012-05-14 11:39:58

2012-05-10 09:50:53

云計算安全

2019-12-04 07:12:41

前端后端web安全

2024-04-11 09:45:31

2012-08-22 10:27:16

2011-10-11 09:13:15

2022-03-10 14:17:11

區塊鏈數據安全技術

2010-09-06 10:47:56

2021-03-15 14:59:28

物聯網互聯網IoT
點贊
收藏

51CTO技術棧公眾號

国产精品果冻传媒| 黄色一级片国产| 男操女视频网站| 日本在线电影一区二区三区| 欧美日本韩国一区二区三区视频 | 青青久在线视频| 日本vs亚洲vs韩国一区三区| 久久亚洲综合国产精品99麻豆精品福利| 久久久久久国产精品日本| 2020日本在线视频中文字幕| 久久免费午夜影院| 91在线精品播放| 国产成人在线免费观看视频| 成人vr资源| 精品日韩一区二区三区| 熟女少妇精品一区二区| 污污网站在线看| 国产午夜精品久久久久久免费视| 999在线观看免费大全电视剧| 亚洲精品中文字幕乱码三区91| 欧美激情成人| 亚洲毛茸茸少妇高潮呻吟| 亚洲色图欧美自拍| 国产精品av一区二区三区| 亚洲视频图片小说| 久久久久久亚洲精品不卡4k岛国| 91久久国语露脸精品国产高跟| 国产婷婷精品| 免费不卡在线观看av| 91视频在线网站| 99精品国产一区二区三区2021 | 色综合久久精品亚洲国产| 永久免费毛片在线观看| 成人av激情人伦小说| 91精品国产91久久综合桃花| 婷婷丁香激情网| 影音先锋男人资源在线观看| 成人午夜大片| 日韩亚洲欧美高清| 色婷婷一区二区三区av免费看| 在线看片福利| 精品成人国产在线观看男人呻吟| 粉嫩av一区二区三区天美传媒| 欧美人xxx| 日本一区二区视频在线观看| 欧美一区激情视频在线观看| 手机看片福利在线观看| av成人免费在线| 国产欧美日韩在线播放| 亚洲av无码片一区二区三区 | 欧美丝袜美女中出在线| 国产免费内射又粗又爽密桃视频| 老司机精品影院| 国产精品剧情在线亚洲| 天天综合色天天综合色hd| 欧美捆绑视频| 久久九九国产精品| 蜜桃传媒视频麻豆第一区免费观看 | 91久久伊人青青碰碰婷婷| 国产精品热久久| 国产曰批免费观看久久久| 成人免费直播live| 99久久精品国产成人一区二区 | 菠萝蜜视频国产在线播放| 国产精品久久久久久久久搜平片| 亚洲精品视频一区二区三区| 色多多视频在线观看| 日韩一区日韩二区| 欧美日韩在线免费观看视频| av免费在线网站| 亚洲一区二区三区视频在线播放| 激情小视频网站| 一区二区三区四区日本视频| 色94色欧美sute亚洲线路一ni| 亚洲狼人综合干| 亚洲国产天堂| 亚洲第一网中文字幕| 国产伦精品一区二区三区妓女| 女人丝袜激情亚洲| 少妇高潮久久77777| 欧美特级一级片| 国产精品永久| 国产欧美日韩高清| 亚洲成a人片在线| 91欧美一区二区| 一区精品在线| wwww在线观看免费视频| 日本高清不卡视频| 中文字幕一区久久| 乱亲女h秽乱长久久久| 亚洲人成绝费网站色www| 精品少妇一区二区三区密爱| 韩国av一区| 国产精品国产三级国产aⅴ9色| 国产欧美综合视频| 久久一二三国产| 成年人三级视频| 欧美激情护士| 欧美一级国产精品| 国产aⅴ激情无码久久久无码| 亚洲精品中文字幕乱码三区91| 国产精品久久久久久影院8一贰佰 国产精品久久久久久麻豆一区软件 | 懂色一区二区三区免费观看| 欧美日韩国产精品一区二区| 黄色免费网站在线| 欧美性极品xxxx娇小| 免费精品99久久国产综合精品应用| www.亚洲一二| 日韩中文视频免费在线观看| 日韩成人高清视频| 婷婷国产精品| 中文字幕日韩综合av| 国产精品18p| 久久精品国产精品青草| 久久大片网站| 亚洲按摩av| 欧美人妖巨大在线| 97超碰在线资源| 伊人影院久久| 91精品久久香蕉国产线看观看| 黄色片在线看| 五月婷婷色综合| 午夜诱惑痒痒网| 久久激情电影| 国产成人精品网站| 理论片中文字幕| 亚洲精品高清在线| 亚洲a级黄色片| 成人影视亚洲图片在线| 欧美一级大片视频| 欧美一区二区三区黄片| 亚洲日本va在线观看| 国产视频在线视频| 欧洲专线二区三区| 欧美一级在线播放| 婷婷五月综合激情| 亚洲国产精品久久久男人的天堂| 亚洲综合20p| 999成人精品视频线3| 国产精品美女999| 国产精品久久久久久久龚玥菲 | 国产精品免费人成网站| 日韩毛片在线免费看| a天堂资源在线| 欧美va亚洲va国产综合| 中文字幕av免费在线观看| 久久99精品久久只有精品| 亚洲第一在线综合在线| 国产综合av| 伊人伊成久久人综合网小说| 怡红院av久久久久久久| 久久精子c满五个校花| 成年人免费在线播放| 九九久久成人| 国产精品激情自拍| 最新av网站在线观看| 亚洲色图欧美激情| 亚洲理论中文字幕| 一级毛片免费高清中文字幕久久网| 91精品久久久久久久久久久| 黄色片网站在线| 日韩欧美卡一卡二| 久久精品国产亚洲av高清色欲 | 欧美视频一区在线| 亚洲ⅴ国产v天堂a无码二区| 老司机精品视频一区二区三区| 亚洲国产一区二区三区在线 | 国产精品免费一区二区三区| 91www在线| 亚洲女人天堂av| 怡红院男人的天堂| 亚洲欧美aⅴ...| 2018国产精品| 亚洲一区二区三区高清不卡| 日本一区高清在线视频| 免费视频观看成人| 久久6免费高清热精品| 色噜噜在线播放| 在线一区二区三区| 国产一区二区播放| 白白色 亚洲乱淫| av无码精品一区二区三区| 91精品国产91久久久久久密臀| 成人综合色站| 成人在线网站| 欧美日韩福利电影| 麻豆影视在线| 日韩亚洲欧美在线| 亚洲成人第一网站| 成人欧美一区二区三区1314| 欧亚乱熟女一区二区在线| 日韩国产欧美三级| 丁香色欲久久久久久综合网| 国产精品羞羞答答在线观看 | av网站免费大全| 欧美丝袜一区二区| 日韩影院一区二区| 久久婷婷国产综合精品青草 | av黄色在线看| 中文字幕一区二区三区在线观看| 性囗交免费视频观看| 日韩成人一级大片| 黄色a级片免费看| 日韩免费av| 美女视频久久| 91成人入口| 成人黄色免费在线观看| 自拍在线观看| 欧美激情一区二区三区在线视频观看| 国产片在线观看| 亚洲国产欧美自拍| 99国产精品99| 欧美精品在线视频| 国产精品久久久久久人| 亚洲第一成年网| 男的操女的网站| 中文字幕久久午夜不卡| 亚洲中文字幕无码一区| 韩国成人福利片在线播放| 99久久国产宗和精品1上映| 在线观看一区| 超碰超碰超碰超碰超碰| 97久久夜色精品国产| 日本精品视频一区| 欧美美女在线直播| 91日韩久久| 国产成人免费av一区二区午夜| 国产97在线观看| 中文字幕人成乱码在线观看 | 国产日产欧美一区二区| 欧美手机在线| 秋霞久久久久久一区二区| 国产伦精品一区二区三区在线播放 | 中文字幕一区综合| 成久久久网站| 色爱区成人综合网| 国产探花一区| 日本精品一区| 欧美日韩在线二区| 日本不卡一区二区三区在线观看| 秋霞综合在线视频| 国产一区免费在线观看| 动漫视频在线一区| 国产精品自拍首页| 国产成人精品福利| 国产精品手机在线| 久久夜色电影| 久久精品国产99精品国产亚洲性色| 无码国模国产在线观看| 91免费版网站在线观看| japanese色系久久精品| 国产伦精品一区二区三区四区免费| 中文字幕久久精品一区二区| http;//www.99re视频| 91精品久久久久久综合五月天| 91视频免费在线观看| 中文字幕一区二区三区四区久久 | 污污网站免费在线观看| 日韩精品免费在线视频观看| 三级国产在线观看| 亚洲图片欧美午夜| av天在线观看| 久久精品国产99国产精品澳门| 性xxxxfjsxxxxx欧美| 欧美精品videofree1080p| 99爱在线观看| 国产成人+综合亚洲+天堂| 123成人网| 91在线播放国产| 盗摄牛牛av影视一区二区| 欧美极品jizzhd欧美| 青青草91久久久久久久久| 最新中文字幕久久| 一区视频在线| 久久久久免费精品| 精品在线免费视频| 午夜影院福利社| 久久精品人人做人人综合 | 午夜理伦三级做爰电影| 国产日韩欧美a| 国产精品 欧美激情| 欧美日在线观看| 一级片在线观看视频| 欧美变态tickling挠脚心| 日本成人一区| 久久伊人色综合| 日韩av一卡| 国产日产亚洲精品| 猫咪成人在线观看| 一区二区三区久久网| 伊人久久亚洲美女图片| 亚洲男人天堂色| 国产成人av电影在线观看| wwwwxxxx国产| 一区二区三区日韩欧美| 久久久久久无码精品大片| 欧美一区日韩一区| 青春有你2免费观看完整版在线播放高清 | 日韩人妻无码一区二区三区| 亚洲欧美区自拍先锋| 91玉足脚交嫩脚丫在线播放| 91精品国产品国语在线不卡| 久久精品蜜桃| 欧美肥婆姓交大片| 欧美韩国亚洲| 国产精品对白刺激久久久| 狠狠操综合网| 国产精品久久中文字幕| 国内精品免费**视频| 人妻熟女aⅴ一区二区三区汇编| 亚洲视频免费在线| 亚洲欧美一二三区| 精品国产91乱码一区二区三区| 色三级在线观看| 国产精品1234| 日韩大胆成人| 大伊香蕉精品视频在线| 国产真实精品久久二三区| 91l九色lporny| 午夜精品成人在线| 亚洲精品成人电影| 久久久国产精品视频| 免费成人美女女| 精品一区二区三区日本| 激情视频一区| 欧美熟妇另类久久久久久多毛| 国产精品视频在线看| 中文字幕激情小说| 亚洲电影第1页| 狂野欧美性猛交xxxxx视频| 亚洲iv一区二区三区| 久久精品国产www456c0m| 男人插女人下面免费视频| 久久免费视频色| 精品国产免费观看| 亚洲国产天堂久久国产91| 欧美xxxx性xxxxx高清| yellow视频在线观看一区二区| 91九色精品| www.色就是色.com| 国产精品萝li| 中文在线资源天堂| 国产一区二区三区欧美| 精品3atv在线视频| 茄子视频成人在线观看 | wwwwwxxxx日本| 国产精品不卡一区| 国产精品久久久久久久久毛片 | 欧美xxxx黑人xyx性爽| 欧美一三区三区四区免费在线看 | 国产三级精品三级在线| 中文字幕综合网| 99久久精品国产成人一区二区| 色综合久久精品亚洲国产| av成人app永久免费| 国产美女主播在线播放| 91丨porny丨首页| 成年人av网站| 最新91在线视频| 成人在线啊v| 日韩精品综合在线| 97久久人人超碰| 免费在线观看av的网站| 色悠悠久久88| 日韩三级av高清片| 欧美日韩成人免费视频| 久久亚洲精精品中文字幕早川悠里| 无码人妻久久一区二区三区 | 国产视频自拍一区| 成人软件在线观看| 一本一道久久a久久精品综合| 国产乱国产乱300精品| 久久精品国产亚洲AV无码男同| 日韩av最新在线观看| 丝袜美腿诱惑一区二区三区| 亚洲一区美女| 成人午夜免费视频| 免费黄色av片| 欧美成人激情视频| 日韩啪啪网站| 视频在线观看免费高清| 夜夜精品浪潮av一区二区三区| 手机亚洲第一页| 91性高湖久久久久久久久_久久99| 精品99视频| 1024手机在线观看你懂的| 日韩欧美国产一区二区三区 | 亚洲伊人久久大香线蕉av| 伊人蜜桃色噜噜激情综合| 免费看日本黄色片| 精品久久久久一区| 日本精品网站| www.av91| 国产精品乱人伦| 亚洲欧美综合在线观看| 91精品美女在线| 国产精品主播| 免费在线一区二区三区| 在线亚洲欧美视频| 岛国av一区|