搜尋
首頁web前端js教程程式碼壓縮混淆加密的實例詳解

程式碼壓縮混淆加密的實例詳解

Jul 17, 2017 pm 02:39 PM
加密壓縮混淆

    一直有人問HTML加密混淆怎麼做,其實這在業界是早已很多人研究過的課題。
假期期間整理一篇文章分享給大家。

    我們先理需求,加密的目的為何?加密到什麼等級?為此我們可以犧牲什麼?我們知道這個世界不存在絕對的安全,加密會被破解、混淆會被反混淆。技術小白、開發者、駭客,是完不同的級別,防範不同級別的人策略都不一樣。防範力道越大,投入代價也越大,例如聘請專業的保全公司。除了投入,我們還需要考慮程式的執行效能和使用者體驗。加密的程式碼在運行時必須解密,混淆後尤其是混淆HTML後,程式的執行效能會下降。是否真的有必要做這類的源碼保護,還需要謹慎取捨。 一般而言,前端的程式碼,負責的是使用者體驗,後端的程式碼,負責更安全的資料處理。 前端不要涉及洩漏太多涉密訊息,那麼加密的意義就不是特別大。

我很少在前端程式碼裡看到值得保護的內容,像是高深的演算法,很多程式碼是沒必要犧牲使用者體驗來保護的。但有些前端程式碼涉及最終用戶的資料安全,此時還是要努力做資料保護的。

1. 降低可讀性

#1.1 壓縮(compression)

很好理解,就是去掉註解、多於的空格、簡化標識符等等。工具很多,YUI Compressor、UglifyJS、Google Closure Compiler等等。

1.2 混淆(obfuscation)

#保證不破壞程式碼執行結果的情況下,讓程式碼變得難以閱讀。常用混淆規則:拆分字串、拆分數組、增加廢代碼、,壓縮其實也有一定混淆功能。本質就是改變輸入程式碼字串的抽象語法樹(AST)的結構。其他工具:v8就是一個,還有mozilla的SpiderMonkey, 知名的esprima,還有uglify;商業混淆服務有:jscramble。

1.3 加密(encryption)

#這裡的加密指文字可逆編碼,是狹義的加密,也就是我們常說的加密啦。這個部分依然是藉助一些工具,如: Packer 、bcrypt等等。

2. 程式碼不會放置在JS檔案中

#將程式碼放在非js檔案中,增加定位難度。這裡常用的方式有兩種:放置到png中,透過HTML Canvas 2D Context取得二進位資料的特性,可以用圖片來儲存腳本資源;放置到css檔案中,利用content樣式可以存放字串的特性,同樣可以。

2.1 png

用png儲存js程式碼,首先需要對png進行編碼,然後使用的時候進行解碼。借助canvas及base64和二進位編碼。

編碼

1、字串轉換成ascii碼; 
2、創建足夠儲存空間的canvas; 
3、將字元填入像素中(忽略alpha值); 
4、取得data url; 
# canvas.toDataURL(“image/png”); 
5、存為png圖片。

function encodeUTF8(str) {  return String(str).replace(  /[\u0080-\u07ff]/g,  function(c) {  let cc = c.charCodeAt(0);return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f);
        }
    ).replace(  /[\u0800-\uffff]/g,  function(c) {  let cc = c.charCodeAt(0);return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3f, 0x80 | cc & 0x3f);
        }
    );
}function request(url, loaded) {  let xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {  if (xmlhttp.readyState == 4)  if (xmlhttp.status == 200)  
                loaded(xmlhttp);
    }
    xmlhttp.open("GET", url, true);
    xmlhttp.send();
}void function(){  let source = '../image/test.js';
    request(source, function(xmlhttp){let text = encodeUTF8(xmlhttp.responseText);let pixel = Math.ceil((text.length + 2) / 3); // 1一个像素存3个字节,  let size = Math.ceil(Math.sqrt(pixel));//console.log([text.length, pixel, size, size * size * 3]);let canvas = document.createElement('canvas');
        canvas.width = canvas.height = size;let context = canvas.getContext("2d"),  
            imageData = context.getImageData(0, 0, canvas.width, canvas.height),  
            pixels = imageData.data;for(let i = 0, j = 0, l = pixels.length; i < l; i++){  if (i % 4 == 3) { // alpha会影响png还原
                pixels[i] = 255;continue;
            }let code = text.charCodeAt(j++);if (isNaN(code)) break;
            pixels[i] = code;
        }
        context.putImageData(imageData, 0, 0);
        document.getElementById(&#39;base64&#39;).src = canvas.toDataURL("image/png");
    });
}();

編碼後的圖片: 
程式碼壓縮混淆加密的實例詳解

解碼

1、載入png; 
2、將png原始尺寸繪製到canvas中; 
3、讀取像素中的字串; 
4、產生對應協定的data url使用。

void function(){  let source = &#39;../image/test.png&#39;;let img = document.createElement(&#39;img&#39;);
    img.onload = function(){  let canvas = document.createElement(&#39;canvas&#39;);
        canvas.width = img.width;
        canvas.height = img.height;let context = canvas.getContext("2d");
        context.drawImage(img, 0, 0);let imageData = context.getImageData(0, 0, canvas.width, canvas.height),  
            pixels = imageData.data;let script = document.createElement(&#39;script&#39;);let buffer = [];for (let i = 0, l = pixels.length; i < l; i++) {  if (i % 4 == 3) continue; // alpha会影响png还原  if (!pixels[i]) break;
            buffer.push(String.fromCharCode(pixels[i]));
        }
        script.src = &#39;data:text/javascript;charset=utf-8,&#39; + encodeURIComponent(buffer.join(&#39;&#39;));
        document.body.appendChild(script);
        script.onload = function(){  
            console.log(&#39;script is loaded!&#39;);
        }
        img = null;
    }
    img.src = source;
}();

這裡需要手動下載編碼後的圖片,我沒有寫自動下載的函數,這又是另一個可以深入探討的問題了,所以不過多擴展。

2.2 css

使用content就簡單多啦。

let div = document.getElementById(&#39;content&#39;);let content = window.getComputedStyle(div, &#39;:before&#39;).content;

只需要跟上面程式碼一樣,新建一個srcript標籤,利用data協議,就可以執行content內保存的js程式碼啦。

3. 防止代码执行被截获

  • 截获 eval() / new Function() 的示例代码

eval = function() {
  console.log(&#39;eval&#39;, JSON.stringify(arguments));
};eval(&#39;console.log("Hello world!")&#39;);Function = function() {
  console.log(&#39;Function&#39;, JSON.stringify(arguments));  return function() {};
};new Function(&#39;console.log("Hello world!")&#39;)();

但是可能不是全局使用:

(function(){}).constructor(&#39;console.log("Hello world!")&#39;)()
  • 截获 constructor 的示例代码

Function.prototype.__defineGetter__(&#39;constructor&#39;, function () {return function () {
        console.log(&#39;constructor&#39;, JSON.stringify(arguments));
    };
});
(function() {}).constructor(&#39;console.log("Hello world!")&#39;);

目前能想到的是判断 eval 是否被重定向

示例,如果 eval 被重定向 z 变量不会被泄露

<span style="font-size: 18px"><code class="language-js hljs  has-numbering">(<span class="hljs-function">function<span class="hljs-params">(x){<span class="hljs-keyword">var z = <span class="hljs-string">&#39;console.log("Hello world!")&#39;;<span class="hljs-built_in">eval(<span class="hljs-string">&#39;function x(){eval(z)}&#39;);
    x();
})(<span class="hljs-function">function<span class="hljs-params">() { <span class="hljs-comment">/* ... */ });<br/><br/><span style="font-size: 18pt; background-color: #ff0000"><strong>uglify介绍<br/></strong></span></span></span></span></span></span></span></span></span></span></code></span>

概述:

<br/>
  • 案例:Cesium打包流程,相关技术点和大概流程

  • 原理:代码优化的意义:压缩 优化 混淆

  • 优化:如何完善Cesium打包流程

<br/>

关键字:Cesium gulp uglifyjs

<br/>

字数:2330 | 阅读时间:7min+

<br/>

 

<br/>

1 Cesium打包流程

<br/>

       如果没有记错,Cesium从2016年初对代码构建工具做了一次调整,从grunt改为gulp。作为一名业余选手,就不揣测两者的差别了。个人而言,gulp和Ant的思路很相似,通过管道连接,都是基于流的构建风格,而且gulp更像是JS的编码风格,自带一种亲切感。

<br/>

gulp.task('task1',['task0'], function() {

    return fun_task1();

});

<br/>

       Task语句是gulp中最常见的,懂了这句话,就等于你看懂脚本了。这句话的意思是,要执行task1,需要先执行task0,而task1的具体工作都在fun_task1方法中。这就是之前说的基于流的构建风格。有了这句话,在命令行中键入:gulp task1,回车执行该指令即可。

<br/>

       先安装Node,环境变量等,并安装npm包后,即可使用gulp打包工具,这里推荐cnpm。环境搭建好后,命令行中键入gulp minify开始打包。完整的过程是build->generateStubs->minify。

<br/>

程式碼壓縮混淆加密的實例詳解

<br/>

Cesium打包流程

<br/>

       build:准备工作,创建Build文件夹;将glsl文件转为js形式;最主要的是createCesiumJs方法,遍历Source中所有js脚本,将所有Object记录到Source/Cesium.js;其他的是范例,单元测试相关模块。

<br/>

       generateStubs:用于单元测试,略。

<br/>

       minify; 首先combineJavaScript主要做了两件事情,打包Cesium和Workers脚本,这是打包的最终结果。Gulp根据指令的不同,比如minify下采用uglify2优化,而combine对应的参数为none,生成路径为CesiumUnminified。

<br/>

       另外,细心的人会发现,combineCesium的实现中有这样一句话path.relative('Source',require.resolve('almond')),这是一个小优化,almond是requirejs的精简包,因此,最终的Cesium.js中包含'almond脚本,内置了requirejs的主要方法。

<br/>

       如上是Cesium打包的主要流程,简单说主要有3+1类个指令:

<br/>
  • Clean

    • 清空文件

  • minify

    • 打包&压缩

  • combine

    • 只打包,不压缩

  • JScoverage

    • 单元测试覆盖率,不了解

<br/>

2 代码优化

<br/>

       对流程有了一个大概了解,下面,我们详细了解一下uglify2过程都做了哪些代码优化,一言以蔽之,压缩,优化,混淆。

<br/>

       uglify2主要有三个参数:-o,-c,-m,-o参数必选,指定输出文件,-c压缩,-m混淆变量名。如下分别为combine、(uglifyjs -o)、(uglifyjs –c -m -o)的文件对比,单位是k:

<br/>

程式碼壓縮混淆加密的實例詳解

<br/>

uglify2的压缩对比

<br/>

       都在一个屋檐下,差距怎么就这么大呢?我们简单说一下从1~2,2~3之间青取之于蓝而胜于蓝的过程。

<br/>

       1~2的过程其实很简单,就是干了三件事,去掉注释, 去掉多余的空格(换行符),去掉不必要的分号(;)。就这三件事情,文件一下子小了一半多,换句话就是平时你写的代码有一大半都是废话,此时你旁边的AI程序员可能会喃喃道来“你们人类好愚蠢~”。

<br/>

       2~3则是很多小细节的综合应用:

<br/>
  • 去掉一些实际没有调用的函数(Dead code);

  • 将零散的变量声明合并,比如 var a; var b;变为var a,b;

  • 逻辑函数的精简,比如if(a) b(); else c()变为a ? b() : c();

  • 变量名的简化,比如var strObject;变为var s;

  • ……

<br/>

       这些小技巧有很多,具体要看不同的压缩工具的考虑优劣,但有些压缩高效的工具并不稳定,可能会破坏语法规范或语意,所以没必要为了几个kb承担过多的风险,目前比较成熟的工具主要有三个uglify2,google closure以及yuicompressor,具体优劣得自己来体会了,我是按照自己的理解给出的先后顺序。最终的效果如下:

<br/>

程式碼壓縮混淆加密的實例詳解

<br/>

Cesium脚本效果

<br/>

       这样的代码只能用单位“坨”来形容了,人类是无法直接读懂的,那浏览器能读懂吗?这是一个好问题!如下是V8引擎对JS语法解析的大概流程:

<br/>

程式碼壓縮混淆加密的實例詳解

<br/>

V8引擎解析JS脚本

<br/>

       下面是在我本机Chrome解析Cesium.js脚本花费时间(脚本从下载完到浏览器解析完的时间差),单位毫秒,因为只测试了一次,可能会有误差,但基本吻合期望值:

<br/>

 程式碼壓縮混淆加密的實例詳解

<br/>

JS脚本解析时间对比

<br/>

       首先因为是本机测试,脚本无论是最大的8M还是最小的2.4M,下载速度都很快,因此我们不讨论(但实际应用中要考虑)脚本下载所需时间。

<br/>

其次,如上图,多了一个source,这是源码情况下,这个时间水分比较大,因为是零散的文件,可以做到按需下载,但因为文件比较琐碎,性能也不高。

<br/>

       结论是,这种JS脚本优化策略对浏览器的影响不大,浏览器看到优化后的代码,可能会愣一会神,但很快就克服了。

<br/>

3实战

<br/>

       知道了代码优化的大概原理,回顾一下代码优化的目的(压缩,优化,混淆),匹配一下结果是否符合期望值。嗯,其一,脚本的大小小了,其二,代码效率也优化了,其三,别人也看不懂了。似乎该做的都已经做了,这个脚本已经很完美了。

<br/>

 程式碼壓縮混淆加密的實例詳解

<br/>

Format后的效果

<br/>

       毛爷爷说,与人斗其乐无穷。确实,前两点的目的达到了,但第三点,还差很多。如上,和刚才的脚本是同一个文件,我只是用Chrome的调试工具format而已。这就是理想和现实之间的差距。

<br/>

       可见,Cesium默认打包工具在压缩和优化上都没有问题,但在混淆上并不充分,当然Cesium本身是开源的,也没必要搞这些。客观说,JS脚本是明码的,所以反编译只是时间和能力的问题,所以不妨换个态度来看待这个问题,增加反编译的成本,当该成本大于购买成本即可

 <br/>

以上是程式碼壓縮混淆加密的實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

神秘的JavaScript:它的作用以及為什麼重要神秘的JavaScript:它的作用以及為什麼重要Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python還是JavaScript更好?Python還是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境