引言:

前端代码是直接暴漏在浏览器中的,很多web攻击都是通过直接debug业务逻辑找到漏洞进行攻击,另外还有些喜欢“不劳而获”的分子暴力盗取他人网页简单修改后用来获利,总体上来说就是前端的逻辑太容易读懂了,本文主要基于JavaScript Obfuscator介绍一下前端混淆的基本思路。

一、JavaScript Obfuscator简介:

  JavaScript Obfuscator是Timofey Kachalov开发的一款JS混淆工具,传统的如uflifyJS等混淆工具主要都是用来压缩代码、降低资源加载时间的,混淆只是附带属性。JavaScript Obfuscator的主要目的就是为了安全,保护前端代码。

二、JavaScript Obfuscator特性:

  JavaScript Obfuscator的混淆原理我就不介绍了,就是用工具对JS进行一下AST(抽象语法树)分析、修改,再重新根据AST生成JS就可以了,uglifyJS也可以实现,给大家推荐一下 esprima http://esprima.org/,github上有一系列工具,用来做混淆和反混淆都非常好用。

  下面我直接讲一下JavaScript Obfuscator的特性,主要特性包括:

  • 关键字提取,增加读取难度:

  JavaScript Obfuscator会将JS里面的关键字,如字符常量等提取出来放到数组中,调用的时候用数组下标的方式调用,这样的话直接读懂基本不可能了,要么反AST处理下,要么一步一步调试,工作量大增。

var test = "hello";
//处理后
var _0x7deb=['hello'];(function(_0xdf8359,_0x2abb06){var _0x4b8e4a=function(_0x3c281c){while(--_0x3c281c){_0xdf8359['push'](_0xdf8359['shift']());}};_0x4b8e4a(++_0x2abb06);}(_0x7deb,0x94));var _0xb7de=function(_0x4c7513,_0x1cb87c){_0x4c7513=_0x4c7513-0x0;var _0x96ade5=_0x7deb[_0x4c7513];return _0x96ade5;};var test=_0xb7de('0x0');

  ps:JavaScript Obfuscator这里做的其实还不够,还可以进一步优化一下,业务相关不在这里说了。

  

  • 关键字编码,进一步增加阅读难度:

  从上面的混淆可以看出,虽然做了关键字提取,但数组中 “hello” 还是清晰可见,为了进一步增加读代码难度,JavaScript Obfuscator利用了JS中16进制编码会直接解码的特性将关键字的Unicode进行了16进制编码。

var test = "hello";
//处理后
var _0x5f41=['\x68\x65\x6c\x6c\x6f'];(function(_0x265fed,_0x59b917){var _0x468703=function(_0x2e4674){while(--_0x2e4674){_0x265fed['push'](_0x265fed['shift']());}};_0x468703(++_0x59b917);}(_0x5f41,0xdd));var _0x15f4=function(_0x551d6e,_0x2697e4){_0x551d6e=_0x551d6e-0x0;var _0x40c0ad=_0x5f41[_0x551d6e];return _0x40c0ad;};var test=_0x15f4('0x0');
  • 关键字加密,增加手动调试难度:

   做了关键字提取后,假如一个人想要破解那么必须要单步调试才可以(先忽略反AST的情况),JavaScript Obfuscator在这里提供了两种关键字加密方式用来对抗单步调试,base64加密和rc4加密,这样处理后单步调试就会加大一些成本。

  

var test = "hello";
//关键字rc4加密
var _0x13b4=['\x77\x70\x4d\x72\x77\x36\x6a\x44\x67\x54\x4d\x3d'];(function(_0x5f376f,_0x4ee5e1){var _0x45c6a7=function(_0x40c574){while(--_0x40c574){_0x5f376f['push'](_0x5f376f['shift']());}};_0x45c6a7(++_0x4ee5e1);}(_0x13b4,0x174));var _0x413b=function(_0x3d9922,_0x37e804){_0x3d9922=_0x3d9922-0x0;var _0xbfa147=_0x13b4[_0x3d9922];if(_0x413b['initialized']===undefined){(function(){var _0x3e4f10=function(){var _0x1699ce;try{_0x1699ce=Function('return\x20(function()\x20'+'{}.constructor(\x22return\x20this\x22)(\x20)'+');')();}catch(_0x2d7a15){_0x1699ce=window;}return _0x1699ce;};var _0x3e7b6b=_0x3e4f10();var _0x2e450c='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';_0x3e7b6b['atob']||(_0x3e7b6b['atob']=function(_0x4fedce){var _0x185f31=String(_0x4fedce)['replace'](/=+$/,'');for(var _0x3c6eda=0x0,_0x48064a,_0x5a5e47,_0x1c810e=0x0,_0x3443c2='';_0x5a5e47=_0x185f31['charAt'](_0x1c810e++);~_0x5a5e47&&(_0x48064a=_0x3c6eda%0x4?_0x48064a*0x40+_0x5a5e47:_0x5a5e47,_0x3c6eda++%0x4)?_0x3443c2+=String['fromCharCode'](0xff&_0x48064a>>(-0x2*_0x3c6eda&0x6)):0x0){_0x5a5e47=_0x2e450c['indexOf'](_0x5a5e47);}return _0x3443c2;});}());var _0x834c2=function(_0x56e849,_0x2be38f){var _0x3aca38=[],_0x1c774d=0x0,_0x49ad4c,_0x595dd4='',_0x5e8aba='';_0x56e849=atob(_0x56e849);for(var _0x295cae=0x0,_0xfbcfa1=_0x56e849['length'];_0x295cae<_0xfbcfa1;_0x295cae++){_0x5e8aba+='%'+('00'+_0x56e849['charCodeAt'](_0x295cae)['toString'](0x10))['slice'](-0x2);}_0x56e849=decodeURIComponent(_0x5e8aba);for(var _0x51a9e3=0x0;_0x51a9e3<0x100;_0x51a9e3++){_0x3aca38[_0x51a9e3]=_0x51a9e3;}for(_0x51a9e3=0x0;_0x51a9e3<0x100;_0x51a9e3++){_0x1c774d=(_0x1c774d+_0x3aca38[_0x51a9e3]+_0x2be38f['charCodeAt'](_0x51a9e3%_0x2be38f['length']))%0x100;_0x49ad4c=_0x3aca38[_0x51a9e3];_0x3aca38[_0x51a9e3]=_0x3aca38[_0x1c774d];_0x3aca38[_0x1c774d]=_0x49ad4c;}_0x51a9e3=0x0;_0x1c774d=0x0;for(var _0x4b8de1=0x0;_0x4b8de1<_0x56e849['length'];_0x4b8de1++){_0x51a9e3=(_0x51a9e3+0x1)%0x100;_0x1c774d=(_0x1c774d+_0x3aca38[_0x51a9e3])%0x100;_0x49ad4c=_0x3aca38[_0x51a9e3];_0x3aca38[_0x51a9e3]=_0x3aca38[_0x1c774d];_0x3aca38[_0x1c774d]=_0x49ad4c;_0x595dd4+=String['fromCharCode'](_0x56e849['charCodeAt'](_0x4b8de1)^_0x3aca38[(_0x3aca38[_0x51a9e3]+_0x3aca38[_0x1c774d])%0x100]);}return _0x595dd4;};_0x413b['rc4']=_0x834c2;_0x413b['data']={};_0x413b['initialized']=!![];}var _0x1cc8d3=_0x413b['data'][_0x3d9922];if(_0x1cc8d3===undefined){if(_0x413b['once']===undefined){_0x413b['once']=!![];}_0xbfa147=_0x413b['rc4'](_0xbfa147,_0x37e804);_0x413b['data'][_0x3d9922]=_0xbfa147;}else{_0xbfa147=_0x1cc8d3;}return _0xbfa147;};var test=_0x413b('0x0','\x29\x38\x24\x34');
  • 控制流变换,增加手动调试难度:

  从上面的JS看其实手动调试的难度还不够高,JavaScript Obfuscator提供了一个控制流平展的能力,可以用控制流来控制逻辑,增加调试的复杂度, 这样处理后会发现当代码量很大的时候手动debug困难就非常大了。

function testFn(){
var test = "hello";
if(test){
test = "hello Devinn";
}
return test;
} //处理后 为了大家能看清将上面的方法都去掉了 这里只处理控制流 并且做了格式化 function testFn() {
var _0x25ac20 = {
'roscj' : 'hello',
'BjrCW' : 'hello\x20Devinn'
};
var _0x52a030 = _0x25ac20['roscj'];
if (_0x52a030) {
_0x52a030 = _0x25ac20['BjrCW'];
}
return _0x52a030;
}
  • 废代码注入,增加手动调试难度:

  如果增加了以上变换以及控制流难度还不够的话,JavaScript Obfuscator还提供了废代码注入的机制,可以随机注入废代码,增加手动调试难度。

  

  • debug防护,禁止手动调试:

  上面的思路都是在增加手动调试的难度,debug防护可以让开启控制台的用户一直卡在debugger控制台上,这里的实现思路比较暴力,一直在调用debugger,实际上可以做些时间上的控制逻辑,大家可以自由发挥。

var test = "hello";
//处理后 已格式化
(function () {
var _0x4ca286 = new RegExp('function\x20*\x5c(\x20*\x5c)');
var _0x4c73ba = new RegExp('\x5c+\x5c+\x20*_0x([a-f0-9]){4,6}');
var _0x215cc4 = _0x203654('init');
if (!_0x4ca286['test'](_0x215cc4 + 'chain') || !_0x4c73ba['test'](_0x215cc4 + 'input')) {
_0x215cc4('0');
} else {
_0x203654();
}
}
());
var test = 'hello';
function _0x203654(_0x53ac71) {
function _0x13f874(_0x10526b) {
if (typeof _0x10526b === 'string') {
return function (_0x1146de) {} ['constructor']('while\x20(true)\x20{}')['apply']('counter');
} else {
if (('' + _0x10526b / _0x10526b)['length'] !== 0x1 || _0x10526b % 0x14 === 0x0) {
(function () {
return !![];
}
['constructor']('debu' + 'gger')['call']('action'));
} else {
(function () {
return ![];
}
['constructor']('debu' + 'gger')['apply']('stateObject'));
}
}
_0x13f874(++_0x10526b);
}
try {
if (_0x53ac71) {
return _0x13f874;
} else {
_0x13f874(0x0);
}
} catch (_0x2c3b47) {} }
  • selfDefending禁止美化代码:

   恶意在试调试代码的时候都会使用devTools的美化功能,将代码美化后进行调试,JavaScript Obfuscator针对这种情况提供了selfDefending的功能,如果美化代码整个JS会报错无法执行,原理就是一个CRC校验,不详细说了。

  • 域名锁定,防止拖JS到本地修改调试:

  上面的debug防护、代码美化都是在JS里面加了控制代码实现的,如果将JS拖到本地去掉后就可以继续破解,JavaScript Obfuscator还做了一个域名锁定的功能,即判断当前域名是否是设置域名,不是就无法执行下去。

  以上就是JavaScript Obfuscator的关键特性,虽然做了上面的各种处理,实际上单个静态JS还是可以破解的,比如 “防止拖JS到本地修改调试” ,实际上把相关代码去除还是可以本地修改调试的,甚至高级一点的可以用反AST的方式来破解调试。私以为看待这个问题要立体的看,整个复杂度上来再想调试成本就非常高了,另外如果对抗反AST破解的情况可以将JS调整成动态,最安全的加密就是一次一密,JS做成同样的就可以了。

三、开发建议:

  所有的混淆器都要满足功能可用,所有全局变量,以及被全局变量引用的变量都不会被混淆器混淆,如对象属性(其实也可以处理,容易出错),开发的时候可以在关键的代码上使用一些函数式编程,混淆会更彻底一点。另外,如果兼容性允许的话可以尝试下asm.js,另一个思路。

四、总结:

  本文主要介绍了一下JavaScript Obfuscator的关键特性,实际上只是想以这个工具为例说一下前端代码保护的一些思路,思路不限于JS。另外还有一些工具,如:jsFuck等,相关处理的思路都可以借鉴,大家自由发挥,有想法的话欢迎交流。

前端混淆--JavaScript Obfuscator的更多相关文章

  1. 前端之JavaScript基础

    前端之JavaScript基础 本节内容 JS概述 JS基础语法 JS循环控制 ECMA对象 BOM对象 DOM对象 1. JS概述 1.1. javascript历史 1992年Nombas开发出C ...

  2. 如何在Visual Studio 2012中发布Web应用程序时自动混淆Javascript

    同Java..NET实现的应用程序类似,Javascript编写的应用程序也面临一个同样的问题:源代码的保护.尽管对大多数Javascript应用公开源代码不算是很严重的问题,但是对于某些开发者来说, ...

  3. 互联网公司前端初级Javascript面试题

    互联网公司前端初级Javascript面试题 1.JavaScript是一门什么样的语言,它有哪些特点?(简述javascript语言的特点)JavaScript是一种基于对象(Object)和事件驱 ...

  4. 第三篇:web之前端之JavaScript基础

    前端之JavaScript基础   前端之JavaScript基础 本节内容 JS概述 JS基础语法 JS循环控制 ECMA对象 BOM对象 DOM对象 1. JS概述 1.1. javascript ...

  5. 好程序员web前端分享javascript关联数组用法总结

    好程序员web前端分享javascript关联数组用法总结,有需要的朋友可以参考下. Hash关联数组定义 代码如下 // 定义空数组 myhash = { } // 直接定义数组 myhash = ...

  6. 前端之JavaScript(二)

    一.概述 本篇主要介绍JavaScript的BOM和DOM操作,在前端之JavaScript(一)中介绍了JavaScript基础知识 1.1.BOM和DOM BOM(Browser Object M ...

  7. Python web前端 05 JavaScript

    Python web前端 05 JavaScript 一.获取元素 1.初识JavaScript /* .. */ #这是多行注释 // #这是单行注释 #JavaScript是一种脚本语言,是一种动 ...

  8. 我的前端规范——JavaScript篇

    相关文章 简书原文:https://www.jianshu.com/p/5918c283cdc3 我的前端规范——开篇:http://www.cnblogs.com/shcrk/p/9271561.h ...

  9. web前端分享JavaScript到底是什么?特点有哪些?

    web前端分享JavaScript到底是什么?特点有哪些?这也是成为web前端工程师必学的内容.今天为大家分享了这篇关于JavaScript的文章,我们一起来看看. 一.JavaScript是什么? ...

随机推荐

  1. 11、Grafana 5.0 新功能特性(译文)

      Grafana v5.0的新功能 这是Grafana有史以来最重大的更新. 本文将详细介绍主要的新功能和增强功能. New Dashboard Layout Engine enables a mu ...

  2. python的位置参数、默认参数、关键字参数、可变参数区别

    一.位置参数 调用函数时根据函数定义的参数位置来传递参数. #!/usr/bin/env python # coding=utf-8 def print_hello(name, sex): sex_d ...

  3. SQL Server2012如何导出sql脚本并且还原数据库

    一  备份数据库 1  选择某一个数据库,右键依次选择:任务==>生成脚本: 2  选择要编写脚本的数据库对象,注意此处可以选择特定的数据库对象,我们可以选择我们需要备份的数据表. 3   在当 ...

  4. spring Boot异步操作报错误: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.self.spring.springboot.Jeep' available

    我也是最近开始学习Spring Boot,在执行异步操作的时候总是汇报如下的错误: Exception in thread "main" org.springframework.b ...

  5. Codeforces 755F PolandBall and Gifts bitset + 二进制优化多重背包

    PolandBall and Gifts 转换成置换群后, 对于最大值我们很好处理. 对于最小值, 只跟若干个圈能否刚好组能 k 有关. 最直观的想法就是bitset优化背包, 直接搞肯定T掉. 我们 ...

  6. 2018-2019-1 20189201《Linux内核原理与分析》第三周作业

    写作业之前,写了时光博物馆参观感受.1978-2018 40年的改革开放历程. 一.C语言中内嵌汇编语言的写法 内嵌汇编的语法如下: asm volatile ( 汇编语句模版: 输出部分: 输入部分 ...

  7. django——url(路由)配置

    URL是Web服务的入口,用户通过浏览器发送过来的任何请求,都是发送到一个指定的URL地址,然后被响应. 在Django项目中编写路由,就是向外暴露我们接收哪些URL的请求,除此之外的任何URL都不被 ...

  8. UWB DWM1000 智能跟踪小车 --[蓝点无限]

    蓝点DWM1000 模块已经打样测试完毕,有兴趣的可以申请购买了,更多信息参见 蓝点论坛 UWB 智能跟踪小车:一共三个UWB模块,手持一个,小车上两个. 通过测量小车上两个模块与手持模块之间的距离, ...

  9. 入门级----黑盒测试、白盒测试、手工测试、自动化测试、探索性测试、单元测试、性能测试、数据库性能、压力测试、安全性测试、SQL注入、缓冲区溢出、环境测试

    黑盒测试 黑盒测试把产品软件当成是一个黑箱子,只有出口和入口,测试过程中只要知道往黑盒中输入什么东西,知道黑盒会出来什么结果就可以了,不需要了解黑箱子里面是如果做的. 即测试人员不用费神去理解软件里面 ...

  10. MySQL数据库表损坏后的修复方法

    步骤:1.sql语句:check table tabTest; 如果出现的结果说Status是OK,则不用修复,如果有Error2.Linux执行: myisamchk -r -q /var/lib/ ...