如何混淆(保护)JavaScript代码?

747

我想制作一个JavaScript应用程序,但不想把代码开源,因此我希望学习如何混淆我的JS代码?这是可能的吗?


16
我很想知道你试图混淆代码的原因,这可能会提供一些必要的背景信息以便给出有帮助的回答。 - JohnFx
49
真正保守秘密的方法就是不将其发送给客户端。如果他们没有这个东西,他们就看不到它。加密发送只会招来少数关心此事的人的麻烦,而其他人即使以明文方式发送,也不会去探究(参见数字版权管理)。 - Donal Fellows
10
这个工具非常好,你可以在线进行混淆。 还有一个混淆的链接。 - RPB
10
混淆您的代码不是一个好主意。这只会给合法用户带来不便(例如:当他们需要修复漏洞时),并且对于有动机反向工程它的人来说没有任何“保护”作用。防止Javascript代码被反向工程是根本不可能的。 - Sven Slootweg
22
我认为不对混淆代码的论点有缺陷。除非你真的认为你的用户可能会修复/报告错误,否则你应该这样做。它可以通过缩小代码来减少加载时间。它永远不会阻止一个真正专注的黑客,但它会减缓他/她的速度,并阻止一些半吊子的攻击尝试。这很容易实现,而且有许多工具(请参见其他答案),我肯定会建议你这样做,因为大多数情况下只有优点,但不要期望它带来真正的安全性或阻止某人在他们确实想要时复制你的代码。唯一的方法是将代码保留在服务器端并使用ajax。 - Benjamin
显示剩余18条评论
22个回答

430

混淆:

尝试使用YUI Compressor。这是一个非常流行的工具,由Yahoo UI团队构建、增强和维护。

您还可以使用:

更新:此问题最初是在2008年提出的,上述技术已过时。您可以使用:

私有字符串数据:

保持字符串值私有是另一个问题,混淆不会带来太多好处。当然,通过将源代码打包成杂乱无章的缩小版,你可以通过混淆达到轻量级的安全性。大多数情况下,查看源代码的是用户,客户端上的字符串值是为他们使用而设计的,因此那种私有字符串值并不经常需要。

如果您确实有一个值,您永远不希望用户看到,您将有几个选项。首先,您可以进行某种加密,在页面加载时进行解密。那可能是最安全的选择之一,但也是很多工作,可能是不必要的。您可以对一些字符串值进行base64编码,那会更容易..但是真正想获取这些字符串值的人可以轻松解码它们。加密是真正防止任何人访问您的数据的唯一方法,而大多数人发现这比他们所需的安全性更高。

附注:

Javascript中的混淆已知会引起一些bug。虽然混淆器变得更好了,但许多公司认为他们从缩小体积gzip压缩中获得了足够的好处,而混淆带来的额外节省并不总是值得麻烦的。如果您想保护您的源代码,也许您会决定这值得您的时间和精力,只是为了使您的代码难以阅读。JSMin是一个很好的选择。


37
我想补充一点,对字符串进行base64编码对安全没有任何益处,因为这是一个非常容易被反转的过程。即使加密也无济于事,如果客户端可以解密。确保字符串的安全性的唯一方法是让客户端只看到加密的字符串,并将其传递给服务器来处理。 - Claudiu
18
进一步处理的服务器。 - Claudiu
10
请注意,可以在此处找到在线的YUI压缩器:http://refresh-sf.com/yui/。 - mtness
10
如果浏览器需要解密字符串值才能使用它们,那么加密这些值与对它们进行base64编码相比仅会带来微不足道的好处。原因在于,您必须向浏览器提供加密密钥,而任何浏览器可以执行的操作用户也可以执行。 - Ben
9
当我使用YUI压缩器进行代码压缩时,我会确保它使用“安全”的压缩方法,即保留分号 --preserve-semi。将私有变量重写为a,b,c等通常是安全的。我还会让压缩器在代码中的每个分号后面加一个换行符 --line-break 0。这样,在生产环境中,如果出现错误,我至少可以有一个有效的参考线索,并且可以在开发副本中找到该代码。否则,您只会在一大堆代码行上遇到错误,而不知道错误在哪里。 - zuallauz
显示剩余5条评论

142

我很惊讶没有人提到谷歌的Closure Compiler。它不仅可以进行代码缩小/压缩,还会分析以找到和删除未使用的代码,并进行最大限度的代码缩小的重新编写。它还可以进行类型检查并警告语法错误。

JQuery最近从YUI Compresser转向Closure Compiler,并看到了“显著的改进”。


65
是的,但最近他们放弃了Closure Compiler并开始使用UglifyJS。在使用Closure Compiler压缩后,JQuery代码存在缺陷。 - Chielus
我想指出的是,如果你正在使用Angular,这个工具可能不会起作用,因为它涉及到依赖注入和参数重命名,除非有一个我看不到的复选框。 - iConnor
1
这是一个有用的工具,但它不支持混淆,这可能就是为什么没有人提到它的原因。 - Madbreaks
1
使用高级优化(https://developers.google.com/closure/compiler/docs/api-tutorial3)的@Madbreaks,可以将代码最小化到混淆点。例如,变量可以重命名以缩短长度。 - Jason Hall
谷歌也不是安全选项。 - Fillipo Sniper

128

混淆代码永远不会真正起到作用。对于任何真正想要获得你的代码的人来说,这只是一个速度障碍。更糟糕的是,它阻止了用户修复漏洞(并将修复发送回给您),使您在现场诊断问题更加困难。这是浪费你时间和金钱。

与律师讨论知识产权法以及您的法律选项。 “开源” 不意味着“人们可以阅读源代码”。相反,开放源代码是一种特定的许可模型,允许自由使用和修改您的代码。如果您不授予此类许可,则复制您的代码的人会违反法律,并且(在大多数国家)您有法律选择阻止他们。

您真正保护代码的唯一方法是不发布它。将重要的代码移到服务器端,并让公共Javascript代码执行Ajax调用。

请参见此处关于混淆器的完整答案。


24
律师可能会比遗失的代码造成更多的成本和问题,所以请仔细考虑并准备足够的资金来聘请律师! - andora
14
我相信找到一个懂JavaScript的律师会很困难,更不用说费用和时间去找“违规者”了。如果一个人从未签署任何文件,他是否真的会违反隐藏在HTML/JavaScript文件中的许可证条款呢? 对于AJAX调用表示赞同。 - Alerty
16
@Alerty 1) 许可证基本上是关于授予使用受版权保护的资料。你没有许可证很难有权使用它。你不必签署许可证以获得这些权利。许可证与合同不同。2a) 由于问题涉及未经允许复制和使用HTML/Javascript,因此许可证并不是“隐藏的”,它就在被拿走的东西上。2b) 没有许可证你很难使用别人的受版权保护的材料。3) 律师不需要了解Javascript,只需要理解知识产权法。 - Schwern
6
别故意装傻。这是要惩罚那些未经许可就在自己的网站上复制文件使用的人。你所说的是合同,而不是许可证。合同需要相互同意并且是一种交易。许可证授予您使用知识产权的权利。许可证是单向的(所有者授予您权利),您不必签署因为您没有放弃任何东西。许多“软件许可协议”实际上都是合同,因为它们超出了对财产的许可,并涉及有时荒谬的事情,比如起诉权。 - Schwern
3
因为提出“雇佣律师”的建议而被踩。多么讨厌的说法。你无法对在互联网上运行的Javascript进行版权保护。这就像版权保护自定义的CSS类一样,祝好运。 - NiCk Newman
显示剩余12条评论

49
您可以对JavaScript源代码进行混淆处理,但由于需要在客户机器上运行所有源代码,因此始终可以通过逆向工程进行还原...我能想到的最好选择是使用服务器端代码完成所有处理,而客户端代码JavaScript只需向服务器本身发送处理请求。否则,任何人都能跟踪代码执行的所有操作。
有人提到了使用base64来保护字符串,这是个糟糕的主意。Base64很容易被那些想要逆向工程您的代码的人识别出来。他们会首先解码它并查看内容是什么。

66
无论我去哪里,当我询问“如何混淆我的Javascript代码?”时,最常见的答案是“你不需要担心这个,因为有人可以解混淆它。”但这并不是一个真正的回答。 - Travis Wilson
2
@Vivek:有点晚了,但我真正想表达的是“服务器端代码”。可以在服务器上运行JavaScript而不是在浏览器中,但我不知道这有多常见。 - Claudiu
8
@Travis:我并没有说“你不必担心这个问题。”我只是说,如果你想要一个闭源程序,你不会想用客户端 JavaScript 来编写它,因为你所做的任何混淆都无法防止它被(相当容易地)反向工程。 - Claudiu
9
好的。这完全没有回答“我如何混淆我的JavaScript”的问题。混淆不是抽象的概念,而是技术上的一个概念。提问者只是简单地问了“如何?” - Madbreaks
2
@Madbreaks:这个问题是在不公开他的代码的情况下提出的。即使技术上的回答是被接受的,但更好的上下文回答(也就是,你真正想做什么?)是,在客户端使用的JavaScript不能不公开源代码,因为无论你如何混淆,每个人都可以看到源代码。无论哪种方式,这两个答案都在这里,人们可以阅读并从中受益。 - Claudiu
显示剩余3条评论

45

有许多免费的JavaScript混淆工具可用,但需要注意的是很难将JavaScript混淆到无法被反向工程。

为此,我使用过几种选项:

  • YUI Compressor。雅虎的JavaScript压缩程序可以很好地压缩代码以提高其加载时间。它有一定程度的混淆效果。基本上,压缩器会更改函数名、删除空格并修改本地变量。这是我最常用的工具。这是一个开源的基于Java的工具。

  • JSMin是由Douglas Crockford编写的一个工具,旨在压缩JavaScript源代码。用Crockford的话来说,“JSMin不混淆,但确实使代码难看。”它的主要目标是缩小源代码的大小,以便在浏览器中更快加载。

  • Free JavaScript Obfuscator。这是一个基于Web的工具,尝试通过对其进行编码来混淆您的代码。我认为其编码(或混淆)形式的权衡可能会以文件大小为代价,但这是个人喜好的问题。


20
由于JavaScript代码必须在客户端机器上运行,因此将其混淆到不能被反向工程化的程度不仅很困难,而且是不可能的 - Schwern
23
关于统计学。有了混淆,以及没有混淆,别人能够获得你的代码的门槛是什么?他们仍然可以获得访问权限,但门槛越高,知情人就越少。知道某些事情的人越少,那么这个事情就越安全。这是标准的安全分类做法。 - Cris Stringfellow
1
@PeterR 在文本编辑器中进行搜索/替换将使您的生活更加困难,尝试阅读或逆向工程它。虽然不是完美的,但通过删除上下文线索,确实增加了额外的烦恼/难度层面。大多数程序员并不像您那样聪明,这就是为什么这是一个很好的威慑因素的原因。 - SED
1
@SED 我不认识一个程序员不能在一分钟内将一堆 [ZER0O00OIFY, ZER0000OIFY, ZEROO00OIFY, ZEROOO0OIFY] 变量替换成至少 [var1, var2,..]。我可以在两分钟内轻松地去除丑陋的代码,重新缩进和搜索/替换变量名。并且,我并不比普通初级开发人员聪明。简单的事实是,没有办法隐藏客户端JS。你最多只能买到5分钟的时间,但那毫无用处。这些东西只是为了向不懂编码的人推销“安全性”。任何写过JS代码的人都不会相信这种垃圾。 - Peter R
4
“我可以在两分钟内直接去丑化代码,重新排版和搜索/替换变量名” - 当然,你可以尝试在一个多遍压缩混淆、20MB的代码库束上进行操作,而这个结构即使有原始注释源代码也需要数周才能理解。更难的是,混淆工具存在并且会故意破坏你的代码,如果缩进、行数等发生改变的话。 - John Weisz
显示剩余2条评论

29

我会做什么:

A. 围攻黑客!

这将会是我虚假/混淆的秘密JavaScript代码启动器的第二部分,就像您在源代码中看到的那样。

这段代码是干什么的?

  1. 加载真实代码
  2. 设置自定义头文件
  3. 发布自定义变量

var ajax=function(a,b,d,c,e,f){
 e=new FormData();
 for(f in d){e.append(f,d[f]);};
 c=new XMLHttpRequest();
 c.open('POST',a);
 c.setRequestHeader("Troll1","lol");
 c.onload=b;
 c.send(e);
};
window.onload=function(){
 ajax('Troll.php',function(){
  (new Function(atob(this.response)))()
 },{'Troll2':'lol'});
}

B. 对代码进行一些混淆处理

那是什么?

  1. 这是与上面相同的Base64编码后的代码。
  2. 这不是秘密JavaScript代码。

(new Function(atob('dmFyIGFqYXg9ZnVuY3Rpb24oYSxiLGQsYyxlLGYpe2U9bmV3IEZvcm1EYXRhKCk7Zm9yKGYgaW4gZCl7ZS5hcHBlbmQoZixkW2ZdKTt9O2M9bmV3IFhNTEh0dHBSZXF1ZXN0KCk7Yy5vcGVuKCdQT1NUJyxhKTtjLnNldFJlcXVlc3RIZWFkZXIoIlRyb2xsMSIsImxvbCIpO2Mub25sb2FkPWI7Yy5zZW5kKGUpO307d2luZG93Lm9ubG9hZD1mdW5jdGlvbigpe2FqYXgoJ1Ryb2xsLnBocCcsZnVuY3Rpb24oKXsgKG5ldyBGdW5jdGlvbihhdG9iKHRoaXMucmVzcG9uc2UpKSkoKX0seydUcm9sbDInOidsb2wnfSk7fQ==')))()

C 创建一个难以显示的php文件,其中包含真正的代码

这个php代码是用来做什么的?

  1. 检查正确的引用者(启动器的域名/目录/代码)
  2. 检查自定义头部
  3. 检查自定义POST变量

如果一切正常,它将显示正确的代码,否则将显示虚假代码或禁止IP,并关闭页面。

<?php
$t1=apache_request_headers();
if(base64_encode($_SERVER['HTTP_REFERER'])=='aHR0cDovL2hlcmUuaXMvbXkvbGF1bmNoZXIuaHRtbA=='&&$_POST['Troll2']=='lol'&&$t1['Troll1']='lol'){
 echo 'ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKSkuaW5uZXJUZXh0PSdBd2Vzb21lJzsNCg==';//here is the SECRET javascript code
}else{
 echo 'd2luZG93Lm9wZW4oJycsICdfc2VsZicsICcnKTt3aW5kb3cuY2xvc2UoKTs=';
};
?>

base64引荐者 = http://here.is/my/launcher.html

SECRET JavaScript = document.body.appendChild(document.createElement('div')).innerText='Awesome';

FAKE = window.open('', '_self', '');window.close();

那么...如果你在SECRET JavaScript中定义事件处理程序,它可能是可访问的...你需要在launchcode之外定义它们,并将其指向嵌套的SECRET函数。

因此...有没有一种简单的方法获取代码? document.body.appendChild(document.createElement('div')).innerText='Awesome';

我不确定这是否有效,但我正在使用Chrome并检查“元素”、“资源”、“网络”、“源代码”、“时间轴”、“配置文件”和“审计”,但我没有找到上述行。

注意1:如果您从Chrome的“检查元素”->“网络”中打开Troll.php网址,则会得到虚假代码。

注意2:整个代码都是为现代浏览器编写的。polyfill需要更多的代码。

编辑

launcher.html

<!doctype html><html><head><meta charset="utf-8"><title></title><script src="data:application/javascript;base64,KG5ldyBGdW5jdGlvbihhdG9iKCdkbUZ5SUdGcVlYZzlablZ1WTNScGIyNG9ZU3hpTEdRc1l5eGxMR1lwZTJVOWJtVjNJRVp2Y20xRVlYUmhLQ2s3Wm05eUtHWWdhVzRnWkNsN1pTNWhjSEJsYm1Rb1ppeGtXMlpkS1R0OU8yTTlibVYzSUZoTlRFaDBkSEJTWlhGMVpYTjBLQ2s3WXk1dmNHVnVLQ2RRVDFOVUp5eGhLVHRqTG5ObGRGSmxjWFZsYzNSSVpXRmtaWElvSWxSeWIyeHNNU0lzSW14dmJDSXBPMk11YjI1c2IyRmtQV0k3WXk1elpXNWtLR1VwTzMwN2QybHVaRzkzTG05dWJHOWhaRDFtZFc1amRHbHZiaWdwZTJGcVlYZ29KMVJ5YjJ4c0xuQm9jQ2NzWm5WdVkzUnBiMjRvS1hzZ0tHNWxkeUJHZFc1amRHbHZiaWhoZEc5aUtIUm9hWE11Y21WemNHOXVjMlVwS1Nrb0tYMHNleWRVY205c2JESW5PaWRzYjJ3bmZTazdmUT09JykpKSgp"></script></head><body></body></html>

Troll.php

<?php $t1=apache_request_headers();if(/*base64_encode($_SERVER['HTTP_REFERER'])=='PUT THE LAUNCHER REFERER HERE'&&*/$_POST['Troll2']=='lol'&&$t1['Troll1']='lol'){echo 'ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKSkuaW5uZXJUZXh0PSdBd2Vzb21lJzsNCg==';}else{echo 'd2luZG93Lm9wZW4oJycsICdfc2VsZicsICcnKTt3aW5kb3cuY2xvc2UoKTs=';}; ?>

2
哦,是的,我也会混淆JavaScript代码。 - cocco
1
这是我刚想到的,戏弄骇客。我希望能看到这样的东西,而不必使用PHP :) - pgarciacamou
9
即使这很有趣,一个能够正确检查网站的网络开发人员,仍然可以以某种方式获取源代码。我真的认为,在你将任何类型的数据放到网上之后,没有任何方法可以隐藏它。 - cocco
这不是任何形式的混淆,我认为。然而,如果知道如何打开控制台,他可能也知道关于base64编码/解码的事情,非常简单。 - T.Todua

20

试用JScrambler。最近我试用了一下,对它印象深刻。 它提供了一系列模板用于混淆,针对那些不太关心细节只想快速完成任务的用户,还提供了预定义设置。此外,您还可以通过选择所需的转换/技术来创建自定义混淆。


8
JScrambler的订阅费非常非常昂贵...最便宜的订阅要求至少3个月,价格为145美元 - 真是太离谱了。 - barbushin
1
现在他们有一个免费计划。其他订阅计划仍然很贵。 - user7610
2
免费计划仅包括优化和缩小文件。 - Jean Hominal
1
免费计划包括优化和缩小文件体积,但是混淆和优化并不相容,抱歉。 - NiCk Newman
2
今天浏览了JScrambler的网站,尤其是价格计划,我没有看到免费选项。只有一个免费试用。 - KDT
我对JScrambler感到非常沮丧,因为它没有一个好的C#客户端,并且API文档没有提供足够的信息让你能够从头开始制作其余的调用,但是他们的客户支持使得我的老板花钱值得。 - Chad Hedgcock

20

解释型语言的问题在于,您需要发送源代码才能使它们工作(除非您有一个将其编译为字节码的编译器,但是反编译相当容易)。

因此,如果您不想牺牲性能,您只能对变量和函数名称进行操作,例如将它们替换为a、b...aa、ab...或a101、a102等。当然,还要尽可能地删除空格/换行符(这就是所谓的JS压缩程序所做的)。
混淆字符串会影响性能,如果您需要实时加密和解密它们。此外,JS调试器可以显示最终值...


18

与大多数其他答案不同,我建议不要使用YUI Compressor;你应该使用Google Closure

这并不是因为它可以压缩更多,而是因为它可以捕获JavaScript错误,例如a = [1,2,3,];,这会导致IE出现问题。


5
在混淆代码之前,检查代码中的错误和不兼容性不管怎样都应该先进行,这与混淆无关。 - phil294

12

我可以推荐Patrick J. O'Neil的JavaScript Utility(链接)。它可以混淆/压缩并且在这方面似乎相当不错。话说,我从未尝试过将其集成到任何构建脚本中。

至于混淆和缩小 - 我不是很喜欢前者。它使得调试变得不可能(错误在第一行...“等等,只有一行”),并且总是需要时间来解包。但是如果你需要的话...好吧。


1
但是混淆并不一定会将代码压缩到一行,它可以简单地更改函数和变量名称或将字符串转换为base64。而代码压缩则将所有代码放在一行上。 - rw-nandemo
现在,UglifyJS似乎是最好的选择。作者也很酷! :) - Tsvetomir Tsonev
关于调试,你可以生成大部分的源代码映射,在测试时包含它们,这样你就可以看到发生错误的具体行数,即使是经过压缩的代码也可以。 - Luca Steeb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接