整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          禁止別人調試自己的前端頁面代碼,這幾種方法很行!

          禁止別人調試自己的前端頁面代碼,這幾種方法很行!

          為啥要禁止?

          • 由于前端頁面會調用很多接口,有些接口會被別人爬蟲分析,破解后獲取數據
          • 為了 杜絕 這種情況,最簡單的方法就是禁止人家調試自己的前端代碼

          無限 debugger

          • 前端頁面防止調試的方法主要是通過不斷 debugger 來瘋狂輸出斷點,因為 debugger 在控制臺被打開的時候就會執行
          • 由于程序被 debugger 阻止,所以無法進行斷點調試,所以網頁的請求也是看不到的
          • 基礎代碼如下:
          /**
          * 基礎禁止調試代碼
          */
          (()=> {
          	function ban() {
          	  setInterval(()=> {
          	    debugger;
          	  }, 50);
          	}
          	try {
          	  ban();
          	} catch (err) { }
          })();
          

          無限 debugger 的對策

          • 如果僅僅是加上面那么簡單的代碼,對于一些技術人員而言作用不大
          • 可以通過控制臺中的 Deactivate breakpoints 按鈕或者使用快捷鍵 Ctrl + F8 關閉無限 debugger
          • 這種方式雖然能去掉礙眼的 debugger,但是無法通過左側的行號添加 breakpoint

          禁止斷點的對策

          • 如果將 setInterval 中的代碼寫在一行,就能禁止用戶斷點,即使添加 logpoint 為 false 也無用
          • 當然即使有些人想到用左下角的格式化代碼,將其變成多行也是沒用的
          (()=> {
            function ban() {
              setInterval(()=> { debugger; }, 50);
            }
            try {
              ban();
            } catch (err) { }
          })();
          


          忽略執行的代碼

          • 通過添加 add script ignore list 需要忽略執行代碼行或文件
          • 也可以達到禁止無限 debugger

          忽略執行代碼的對策

          • 那如何針對上面操作的惡意用戶呢
          • 可以通過將 debugger 改寫成 Function("debugger")(); 的形式來應對
          • Function 構造器生成的 debugger 會在每一次執行時開啟一個臨時 js 文件
          • 當然使用的時候,為了更加的安全,最好使用加密后的腳本
          // 加密前
          (()=> {
            function ban() {
              setInterval(()=> {
                Function('debugger')();
              }, 50);
            }
            try {
              ban();
            } catch (err) { }
          })();
          
          // 加密后
          eval(function(c,g,a,b,d,e){d=String;if(!"".replace(/^/,String)){for(;a--;)e[a]=b[a]||a;b=[function(f){return e[f]}];d=function(){return"\w+"};a=1}for(;a--;)b[a]&&(c=c.replace(new RegExp("\b"+d(a)+"\b","g"),b[a]));return c}('(()=>{1 0(){2(()=>{3("4")()},5)}6{0()}7(8){}})();',9,9,"block function setInterval Function debugger 50 try catch err".split(" "),0,{}));
          


          終極增強防調試代碼

          • 為了讓自己寫出來的代碼更加的晦澀難懂,需要對上面的代碼再優化一下
          • 將 Function('debugger').call() 改成 (function(){return false;})['constructor']('debugger')['call']();
          • 并且添加條件,當窗口外部寬高和內部寬高的差值大于一定的值 ,我把 body 里的內容換成指定內容
          • 當然使用的時候,為了更加的安全,最好加密后再使用
          (()=> {
            function block() {
              if (window.outerHeight - window.innerHeight > 200 || window.outerWidth - window.innerWidth > 200) {
                document.body.innerHTML="檢測到非法調試,請關閉后刷新重試!";
              }
              setInterval(()=> {
                (function () {
                  return false;
                }
                ['constructor']('debugger')
                ['call']());
              }, 50);
            }
            try {
              block();
            } catch (err) { }
          })();
          




          禁止的方法有了,如何反禁止呢? 你想到了嗎?

          文最初發表于HTTP Toolkit網站,經原作者 Tim Perry 授權由 InfoQ 中文站翻譯分享。

          萬物都會有終結,HTTP API 也不例外。不論你的 API 今天看上去多么偉大,遲早有一天你會想發布一個全新的版本,新版本能更好地解決相同問題,在各方面可能都會有所改善,但是它因為有了新參數,與舊版本也無法兼容,或者你只是想徹底關閉舊的 API。總而言之,你現在的 API 不會永遠存在。

          但是,這并非輕而易舉就能完成的,因為你的 API 有客戶端。如果你關閉端點、參數或整個 API 而沒有做出恰當的警告的話,那他們肯定會非常不爽。

          那么,該怎樣安全地關閉 API,讓你的用戶盡可能地感到輕松愉快呢?

          在這方面,我們有正確的做事方式,包括兩個新的頭信息草案,它們正在被新的 IETF “Building Blocks for HTTP APIs”工作組進行標準化,旨在形成一個精確的過程。我們了解一下。

          制定計劃

          初始第一步:檢查相關的 API 是否真的有客戶端。

          希望你能有某些 API 的度量指標,至少在某些地方存有日志。如果沒有的話,那把它們添加上,如果你有這些東西的話,并且你能確定沒有人再使用這個 API 了,那么恭喜你,你贏了。現在,你就可以把它關掉,刪掉代碼,不要再管這篇文章了,好好睡一覺。

          下一個問題,如果比較遺憾,你無法去睡覺的話,那就要問問自己,除了關閉這個 API,還有沒有其他方案。你關閉的所有東西都有可能破壞別人的代碼,并且會消耗他們的時間來修復這些問題。如果 API 能繼續運行的話,對客戶端的生態系統和整個 web 的健康都是有好處的。

          在很多場景下,舊的 API 可以在內部進行轉換,透明地轉化成對新 API 的調用,這樣可以避免維護兩個完全獨立的版本。這是Stripe的API版本管理方式的一個基本組成部分,他們在所有發生變化的 API 中都包含了轉換,以確保對不兼容的舊版本 API 的請求能繼續像以前那樣運行,根據需要自動轉換請求和響應從而可以使用較新的代碼。

          這樣的轉換并不總是可行的,而且如果永遠這樣做的話會帶來明顯的額外復雜性,但是如果你可以做到這一點的話,就能為用戶提供非常有價值的穩定性,并且可以節省大量廢棄舊版本或維護舊版本相關的工作。

          但是,如果這個服務/端點/參數已經用到了生產環境,而且繼續支持它是不現實的做法,那么它必須要被淘汰。

          要實現這一點,我們就要有一個計劃。我們首先要問自己三個關鍵的問題:

          • 你希望用戶該怎么做?常見的答案包括:
          • 升級到相關功能的一個更新的、依然能得到支持的版本
          • 使用一些可替代的端點/參數/服務
          • 使用不同的服務,它們與你無關,不需要你關心
          • 用戶應該何時遷離這個 API?你所提出的替代方案現在就可以用了嗎?
          • 截止時間是什么時候?也就是,這個 API 何時會完全停止使用?(如果不能完全確定的話,你可以稍微延遲回答這個問題)。

          計劃準備就緒之后,我們就該把它告訴人們了。

          溝通

          首先,要把這一決定告訴人們。

          發郵件到郵件列表,在 Twitter 或微博上發帖,如果有 API 規范的話,對其進行更新(比如,OpenAPI 在operations和parameters上有一個deprecated字段),并在相關的在線文檔上大聲強調這一點。

          你應該包含上文提到的所有信息:他們應該做些什么作為替代方案,你建議他們什么時候開始遷移以及他們必須要進行遷移的最后期限(如果已經確定期限的話)。

          在將這些信息告訴給人們后,接下來就該告訴計算機,而這就是新的 IETF 頭信息可以發揮作用的地方。

          Deprecation 頭信息

          Deprecation頭信息能告訴客戶端請求的資源現在依然像以前那樣運行,但是這種方式已經不再推薦使用了。通過一個簡單的 HTTP 頭信息,我們就可以聲明這一點:

          Deprecation: true

          另外,我們還能提供一個日期。這個日期告訴用戶他們何時該開始進行遷移。這個日期可以是一個過去時間(這代表他們應該立即開始遷移),也能是將來時間(通常這意味著他們要遷移到的新環境還沒有準備就緒)。如下所示:

          Deprecation: Thu, 21 Jan 2021 23:59:59 GMT

          如果你要廢棄整個端點或服務,那么你可以在每個響應中都帶上這樣的頭信息。如果你想要廢棄的是一個具體的特性,可能是一個參數、請求方法或者請求體中的某個特定字段的話,那么你應該在該特性被使用的時候才在響應中包含這個頭信息。

          為了給客戶端更多的信息,我們還可以使用Link HTTP 響應頭信息鏈接至端點或人類易讀的文檔。在同一個Link頭信息中,我們可以包含多個這樣的鏈接,只需要使用逗號進行分割即可(后面我們會看到一個完整的例子)。該規范定義了四個與 API 廢棄相關的鏈接:

          Deprecation 鏈接

          我們可以為 deprecation 鏈接指向一個人類易于閱讀的描述:

          Link: <https://developer.example.com/deprecation>; rel="deprecation"; type="text/html"

          這是告訴用戶發生了什么以及他們該怎么辦的主要方式。你應該始終使用它。如果還沒有完整的詳情和最終的關閉日期,那么即使只是一個占位符,這也是很有幫助的。在這種情況下,不要忘記讓用戶訂閱更新,這可以采用郵件列表、RSS 或其他類似的方式來實現。

          Latest-Version 鏈接

          如果你希望客戶端轉移至 API 相同端點的最新版本,那么可以使用該鏈接指向它,如下所示:

          Link: <https://api.example.com/v10/customers>; rel="latest-version"

          Successor-Version 鏈接

          如果你的 API 有多個可用的版本,通常最好每次向前遷移一個版本,而不是直接從最老的、現已廢棄的版本跳到最新的版本。為了幫助解決這個問題,我們鏈接至已廢棄版本的下一個版本,而不是最新版本,如下所示:

          Link: <https://api.example.com/v2/customers>; rel="successor-version"

          Alternate 鏈接

          如果該 API 沒有新的等價版本,用戶最好遷移到一個完全不同的資源,它可能是一個很好的替代方案,那么我們使用 alternate 鏈接來指明這一點,如下所示:

          Link: <https://api.example.com/v2/users/123/clients>; rel="alternate"

          Sunset 頭信息

          如果你知道了 API 何時完全關閉的話,那么就應該添加一個Sunset頭信息。

          Sunset 頭信息告訴客戶端 API 何時會停止運行。這是一個強制的截止時間:API 客戶端必須要在這個日期前進行遷移,我們承諾在這個時間前不會破壞任何事情。

          在這里,我們必須要提供一個時間,它應該是一個未來的時間。不過,如果它是一個過去的時間,這也是可以的:此時就相當于說“這個 API 會在任意時刻關閉,你需要立即停止使用它”。它如下所示:

          Sunset: Tue, 20 Jul 2021 23:59:59 GMT

          這非常簡單,它不僅可以用到 API 關閉的場景中:我們能用它來標記將來 URL 遷移的 HTTP 重定向,或者表明特定 URL 有限的生命周期(適用于臨時性的內容,或者適用于具有監管要求的特定資源,比如數據保留策略)。它所說明的就是“這個端點可能在該日期后不會再按照你的預期運行,請做好準備”。

          Sunset 鏈接

          該規范也提供了一個 Sunset 鏈接的關系。按照設計,它會鏈接至關于關閉特定端點更加詳細的信息(如果你有 deprecation 鏈接的話,它們可能會是同一個)或者關于服務的通用 Sunset 策略。如下所示:

          Link: <http://developer.example.com/our-sunset-policy>;rel="sunset";type="text/html"

          在這里我們也要指出,通用的 Sunset 策略是非常有用的!Sunset 策略會告訴客戶端,當我們關閉端點的時候(比如,一年后替代方案上線),用戶該如何確保他們能得知這一情況(郵件列表、狀態頁面、HTTP 頭信息等)以及他們通常應該做些什么(更新、檢查文檔、遵從Link頭信息)。

          如果馬上就要廢棄某個 API 的話,添加這樣的鏈接作用其實不大,但是如果你能在一年前就將其發布出去的話,你的客戶端可能已經為此做好了準備。

          除此之外,發布 Sunset/Deprecation 策略的最好時間就是現在。如果你恰好正以某種方式編寫 Deprecation 文檔的話,這么做是值得考慮的。

          組合到一起

          按照設計,這些組成部分能很好地協作。例如,為了表明某個最近廢棄的 API,該 API 會在 6 個月內徹底關閉,我們要鏈接至文檔并提供下一個版本的直接鏈接,那么我們應該在響應中包含如下的頭信息鏈接:

          Deprecation: Thu, 21 Jan 2021 23:59:59 GMT
          Sunset: Tue, 20 Jul 2021 23:59:59 GMT
          Link: <https://api.example.com/v2/customers>; rel="successor-version",
              <https://developer.example.com/shutting-down-customers-v1>; rel="deprecation"

          漸進式關閉

          如果所有這些都已經準備到位,并且 sunset 截止時間已過,那么我們就可以將 API 關閉了。

          但是,這并不意味著你需要立即且徹底消滅該 API。漸進式關閉能有助于確保任何使用該 API 的所有客戶端都有最后的機會在它徹底消失前得到最后一次警告。GitHub 在 2018 年移除一些加密支持的時候曾經這樣做:首先禁用一個小時,然后啟用它,最后在兩周后徹底禁用了它。

          這里還有另外一個技巧:安卓在 2015 年為已廢棄的原生API增加了越來越多的延遲,在徹底關閉 API 前,最終達到了 16 秒的等待。

          這些漸進式的關閉為那些錯過截止日期的客戶端提供了一些靈活性,并且能幫助那些沒有注意到廢棄時間點的客戶端,從而能在 API 徹底關閉之前處理一些問題。

          謹慎行事

          不管采用哪種方式,只要你盡了最大的努力去溝通關于 API 關閉的事情,那么現在就可以關閉端點/特性/整個服務,刪除代碼,然后睡個好覺。

          像這樣小心謹慎地進行廢棄和關閉,可以讓你的客戶端盡可能清楚地知道他們該如何依賴你的 API,何時需要采取行動,以及他們需要做什么。這種變更可能是一件大事兒,這些信息是很重要的。

          這些新的草案頭信息讓我們不僅可以與人類溝通,還能將這些信息暴露給自動化系統。隨著這些頭信息的普及,我很高興地開始看到有更多的工具建立在它們之上。通用的 HTTP 客戶端可以根據這些數據自動記錄有用的警告日志,API 生成器本身也能根據 API 規范處理越來越多的問題,而 HTTP 調試器(如HTTP Toolkit)可以在截獲的實時流量中為你突出顯示廢棄端點的使用。這是一個令人激動的時刻,我們可以開始安全地關閉 API 了!

          需要注意的是,這些頭信息是 HTTP 規范的草案。在最終確定前,它們有可能會發生變化。也就是說,它們經歷了幾輪修改,從現在開始,它們不太可能發生巨大的變化,現在能廣泛測試它們了。

          不過這也意味著還有時間進行反饋! 如果你對它們的工作方式和如何更好地運行有想法的話,請與“Building Blocks for HTTP APIs”工作組聯系。你可以給郵件列表發郵件:httpapi@ietf.org,或者在這里查看之前的郵件列表討論。

          原文鏈接:

          https://httptoolkit.tech/blog/how-to-turn-off-your-old-apis/

          這兩天碰到一個需求:在用戶刷新頁面或者關閉頁面的時候,前端要給后臺發一條請求,釋放該頁面的授權占用。

          分析了一下,這不就是在頁面卸載時發請求嘛,三下五除二就實現一版:

          window.addEventListener("beforeunload", ()=> {
          let oReq=new XMLHttpRequest();
          oReq.open("POST", "http://127.0.0.1:1991/loginout");
          oReq.send(JSON.stringify({name: "編程三昧"}));
          

          測試發現:

          • 刷新頁面時基本滿足需求(偶爾也會有后臺接收不到請求的現象,但概率很低)
          • 關閉頁面時,后臺接收不到請求

          既然異步 Ajax 不行,那就試試同步的吧,結果直接報錯了:

          搜了一下,解釋如下:

          Chrome now disallows synchronous XHR during page dismissal when the page is being navigated away from or closed by the user. This involves the following events (when fired on the path of page dismissal): beforeunload, unload, pagehide, and visibilitychange.

          概括起來就是:對現在的 Chrome 來說,在頁面導航離開或者被用戶關閉時,不允許發送同步 XHR 請求,涉及到的事件有:beforeunload、unload、pagehide 和 visibilitychange。

          雖然問題沒解決,但是卻長知識了,這波不太虧!

          navigator.sendBeacon()

          后來通過搜索,看到有一個接口是專門來干這事的,那就是 navigator.sendBeacon()

          描述

          這個方法主要用于滿足統計和診斷代碼的需要,這些代碼通常嘗試在卸載(unload)文檔之前向web服務器發送數據。

          語法

          navigator.sendBeacon(url, data);
          

          參數

          • url 表明 data 將要被發送到的網絡地址。
          • data 參數是將要發送的 ArrayBufferViewBlobDOMString 或者 FormData 類型的數據。

          返回值

          當用戶代理成功把數據加入傳輸隊列時,sendBeacon() 方法將會返回 true,否則返回 false

          實現

          既然有了接口,那實現起來就簡單了。

          代碼

           window.addEventListener("beforeunload", (e)=> {
              const data={name: "編程三昧"};
              window.navigator.sendBeacon("http://127.0.0.1:1991/loginout", JSON.stringify(data));
          });
          

          效果

          不管是刷新頁面還是關閉頁面,后臺都能接收到前端發送過來的請求,完美實現需求。

          總結

          瀏覽器現在功能越來越強大,支持的 API 也越來越豐富,放在之前很難實現的功能,現在可能就是輕而易舉的事,還是要多關注技術動態。

          ~

          ~本文完,感謝閱讀!

          ~

          學習有趣的知識,結識有趣的朋友,塑造有趣的靈魂!

          大家好,我是〖編程三昧〗的作者 隱逸王,我的公眾號是『編程三昧』,歡迎關注,希望大家多多指教!

          你來,懷揣期望,我有墨香相迎! 你歸,無論得失,唯以余韻相贈!

          知識與技能并重,內力和外功兼修,理論和實踐兩手都要抓、兩手都要硬!


          主站蜘蛛池模板: 风间由美性色一区二区三区| 一区二区高清在线| 亚洲一区二区三区免费视频| 精品国产一区在线观看 | 精品一区二区三区在线观看l | 亚洲国产精品第一区二区| 亚洲色偷精品一区二区三区| 亚洲AV无码一区二区三区DV | 国产日韩综合一区二区性色AV| 伊人激情AV一区二区三区| 琪琪see色原网一区二区| 无码毛片一区二区三区中文字幕 | 国内精品视频一区二区八戒| 亚洲一区在线观看视频| 曰韩人妻无码一区二区三区综合部 | 国产在线一区二区三区| 国产一区二区福利| 久久久久久综合一区中文字幕 | 精品国产一区二区三区久久狼| 精品国产伦一区二区三区在线观看 | 日韩精品无码一区二区三区| 日韩一区二区视频| 中文乱码字幕高清一区二区| 精品少妇一区二区三区视频| 国精品无码一区二区三区在线| 国产一区二区三区高清视频| 人妻天天爽夜夜爽一区二区 | 国产日韩视频一区| 亚洲无线码一区二区三区| 竹菊影视欧美日韩一区二区三区四区五区 | 亚洲愉拍一区二区三区| 天堂不卡一区二区视频在线观看| 免费萌白酱国产一区二区三区| 日产亚洲一区二区三区| 一区二区三区四区国产| 精品黑人一区二区三区| 亚洲中文字幕丝袜制服一区 | 国产精品无码一区二区三区电影| 无码夜色一区二区三区| 日韩欧美一区二区三区免费观看| 国产一区二区中文字幕|