【知识整理】vue-cli脚手架开发项目如何进行js高级加密

一。最近收到一个对js源码进行加密,以防止关键js源代码泄露的需求!由于我们的项目是基于vue-cli脚手架开发的,因此首先想到的是其中的webpack插件UglifyJsPlugin是否提供js代码加密的配置。查询UglifyJsPlugin官方手册后发现该插件提供代码压缩及混淆功能,可以对代码进行压缩,变量、函数名替换为简单字母,降低了源码的可读性,一定程度上达到了加密的目的,但是加密级别没有达到我们的要求。因此只能亲自动手找找是否有现成的开源加密算法,拿过来借用一下。
二。在网上找到了一个名为'jjencode'的js加密算法,这里贴出他的网站:https://www.sojson.com/jjencode.html,通过此算法对js加密后台代码如下图:

可以看到加密后已经根本看不出任何js语言的痕迹,更不可能看出其中的具体算法是什么,这种的加密级别基本已经符合我们的需求了。问题来了,加密算法虽然有了,但是我们不能每次重新打包后都手动加密代码后覆盖原文件,这使得加密流程变得繁琐,如果在每次打包后能够自动加密就好了。怎么样才能实现自动加密呢,这就需要我们手写一个自动加密的插件了。
三。如果对webpack的插件机制不了解的,可以参考这篇文章:https://juejin.im/entry/5a4cb7906fb9a04500037399。我将插件命名为'JsEncodePlugin',源码如下:

// 1、js-encode-plugin.js 文件(webpack的js加密插件)
const fs = require('fs');//node的文件系统模块,用于读写及操作文件
const path = require('path');//node提供的一些用于处理文件路径的小工具
var chalk = require('chalk')//用于向控制台输出带颜色的问题提示
// 2、模块对外暴露的 js 函数
function JsEncodePlugin(pluginOptions) {
  this.options = pluginOptions;
}

// 3、原型定义一个 apply 函数,并注入了 compiler 对象
JsEncodePlugin.prototype.apply = function (compiler) {
  const _this = this;
  // 4、挂载 webpack 事件钩子(这里挂载的是 after-emit 事件,在将内存中 assets 内容写到磁盘文件夹之后触发的webpack生命周期钩子)
  compiler.plugin('after-emit', function (compilation, callback) {
      // ... 内部进行自定义的编译操作
      // 5、操作 compilation 对象的内部数据
      console.log(chalk.cyan('\n jsencode start.\n'))
      var filePath = path.resolve(__dirname, _this.options.assetsPath);//设置需要加密的js文件路径,_this.options.assetsPath为插件配置中传过来的需要加密的js文件路径
      filterFile(filePath);
      function filterFile(fp){
        fs.readdir(fp, (err, files)=>{//读取该文件路径
          if(err){
            console.log(chalk.yellow(
              '读取js文件夹异常:\n' +
              err.message + '\n'
            ))
            return;
          }
          files.forEach((filename)=>{//遍历该路径下所有文件
            if(_this.options.jsReg.test(filename)){//利用正则匹配我们要加密的文件,_this.options.jsReg为插件中传过来的需要加密的js文件正则,用以筛选出我们需要加密的js文件。
              var filedir = path.resolve(fp, filename);
              fs.readFile(filedir, 'utf-8', (err, data)=>{//读取文件源码
                if(err){
                  console.log(chalk.yellow(
                    '读取js文件异常:\n' +
                    err.message + '\n'
                  ))
                  return;
                }
		//调用jjencode函数对源码进行jjencode加密,_this.options.global为插件配置中传过来的加密使用的全局变量名,将在jjencode函数中作为第一个参数传入
                let result = jjencode(_this.options.global, data);
                fs.writeFile(filedir, result, (err)=>{//将加密后的代码写回文件中
                  if(err){
                    console.log(chalk.yellow(
                      '写入加密后的js文件异常:\n' +
                      err.message + '\n'
                    ))
                    return;
                  }
                  console.log(chalk.cyan('  jsencode complete.\n'))
                })
              })
            }
          })
        })
      }
      //js加密函数
      function jjencode( gv, text )
			{
				var r="";
				var n;
				var t;
				var b=[ "___", "__$", "_$_", "_$$", "$__", "$_$", "$$_", "$$$", "$___", "$__$", "$_$_", "$_$$", "$$__", "$$_$", "$$$_", "$$$$", ];
				var s = "";
				for( var i = 0; i < text.length; i++ ){
					n = text.charCodeAt( i );
					if( n == 0x22 || n == 0x5c ){
						s += "\\\\\\" + text.charAt( i ).toString(16);
					}else if( (0x20 <= n && n <= 0x2f) || (0x3A <= n == 0x40) || ( 0x5b <= n && n <= 0x60 ) || ( 0x7b <= n && n <= 0x7f ) ){
						s += text.charAt( i );
					}else if( (0x30 <= n && n <= 0x39 ) || (0x61 <= n && n <= 0x66 ) ){
						if( s ) r += "\"" + s +"\"+";
						r += gv + "." + b[ n < 0x40 ? n - 0x30 : n - 0x57 ] + "+";
						s="";
					}else if( n == 0x6c ){ // 'l'
						if( s ) r += "\"" + s + "\"+";
						r += "(![]+\"\")[" + gv + "._$_]+";
						s = "";
					}else if( n == 0x6f ){ // 'o'
						if( s ) r += "\"" + s + "\"+";
						r += gv + "._$+";
						s = "";
					}else if( n == 0x74 ){ // 'u'
						if( s ) r += "\"" + s + "\"+";
						r += gv + ".__+";
						s = "";
					}else if( n == 0x75 ){ // 'u'
						if( s ) r += "\"" + s + "\"+";
						r += gv + "._+";
						s = "";
					}else if( n < 128 ){
						if( s ) r += "\"" + s;
						else r += "\"";
						r += "\\\\\"+" + n.toString( 8 ).replace( /[0-7]/g, function(c){ return gv + "."+b[ c ]+"+" } );
						s = "";
					}else{
						if( s ) r += "\"" + s;
						else r += "\"";
						r += "\\\\\"+" + gv + "._+" + n.toString(16).replace( /[0-9a-f]/gi, function(c){ return gv + "."+b[parseInt(c,16)]+"+"} );
						s = "";
					}
				}
				if( s ) r += "\"" + s + "\"+";
 
				r = 
				gv + "=~[];" + 
				gv + "={___:++" + gv +",$$$$:(![]+\"\")["+gv+"],__$:++"+gv+",$_$_:(![]+\"\")["+gv+"],_$_:++"+
				gv+",$_$$:({}+\"\")["+gv+"],$$_$:("+gv+"["+gv+"]+\"\")["+gv+"],_$$:++"+gv+",$$$_:(!\"\"+\"\")["+
				gv+"],$__:++"+gv+",$_$:++"+gv+",$$__:({}+\"\")["+gv+"],$$_:++"+gv+",$$$:++"+gv+",$___:++"+gv+",$__$:++"+gv+"};"+
				gv+".$_="+
				"("+gv+".$_="+gv+"+\"\")["+gv+".$_$]+"+
				"("+gv+"._$="+gv+".$_["+gv+".__$])+"+
				"("+gv+".$$=("+gv+".$+\"\")["+gv+".__$])+"+
				"((!"+gv+")+\"\")["+gv+"._$$]+"+
				"("+gv+".__="+gv+".$_["+gv+".$$_])+"+
				"("+gv+".$=(!\"\"+\"\")["+gv+".__$])+"+
				"("+gv+"._=(!\"\"+\"\")["+gv+"._$_])+"+
				gv+".$_["+gv+".$_$]+"+
				gv+".__+"+
				gv+"._$+"+
				gv+".$;"+
				gv+".$$="+
				gv+".$+"+
				"(!\"\"+\"\")["+gv+"._$$]+"+
				gv+".__+"+
				gv+"._+"+
				gv+".$+"+
				gv+".$$;"+
				gv+".$=("+gv+".___)["+gv+".$_]["+gv+".$_];"+
				gv+".$("+gv+".$("+gv+".$$+\"\\\"\"+" + r + "\"\\\"\")())();";
				//console.log(r);
				return r;
			}
      // 6、执行 callback 回调
      callback();
  });
};

 

// 暴露 js 函数
module.exports =JsEncodePlugin;

四。插件写好后我们要在webpack的配置文件webpack.prod.conf.js中引入该插件,该文件为生产环境中webpack的配置入口。它也依赖于webpack.base.conf.js、utils.js和config/index.js。当运行'npm run build'做线上环境打包时会执行该文件代码。我们可以注释掉其中UglifyJsPlugin插件了,因为UglifyJsPlugin插件压缩和加密的功能,我们开发的JsEncodePllugin插件都能实现并且做得更好。

五。引入我们开发的JsEncodePlugin插件后,运行'npm run build'做一个线上打包后,我们就可以查看加密后的文件了。

来源:https://blog.csdn.net/qq_19891827/article/details/80908588

总结:该方式有一个致命的点,就是加密以后的vue文件特别的大,1m的文件要跨大到接近20倍,这样是万万不能上线的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值