如何保护js代码

2023/9/24 前端

# 背景

  • 系统安全问题日益变成影响和制约网络应用发展的一个重要因素,如今,越来越多的安全产品厂商在考虑关注软件开发的整个流程,将安全检测与监测融入需求分析、概要设计、详细设计、编码、测试等各个阶段以全面的保证应用安全

  • 对于前端场景来说,作为数据采集的最前线,js 代码始终暴露在外,并没有办法限制攻击者获取源码,目前主流的解决方式是在源头做手脚,即对 js 代码做加密、压缩、混淆

# 介绍

# 加密

  • 提到加密,我们自然会想到众多与对称加密、非对称加密以及散列加密相关的算法,比如 AWS 算法、RSA 算法与 MD5 算法等。简单理解就是加密即是将明文变为密文的过程,与此类似,将密文变为明文的过程被称为解密

  • 在传统的 B-S 架构下,前端通过公钥进行加密处理的数据可以在后端服务器再通过相应私钥进行解密来得到原始数据,但是对于前端的业务代码而言,由于浏览器本身无法识别运行这些被加密过的源代码,因此实际上传统的加密算法并不能帮助我们解决如何完全黑盒化前端业务逻辑代码这一问题。既然无法完全隐藏前端业务逻辑代码的实际执行细节,那我们就从另一条路以降低代码可读性的方式来伪黑盒化前端业务逻辑代码

# 压缩

  • 所谓压缩其实是和性能优化有关,主要是为了减少体积大小

  • 目前主流的 UglifyJS、YUI Compressor 等工具内部做的事有:去除多余字符、空格、换行及注释,把长变量名改为统一风格的短变量名等

  • 虽然通过压缩后的代码体积减少了,可读性变差了,但是通过格式化代码后,还是能成为突破口

# 混淆

  • 很显然通过 加密 和 压缩 并不能够很好的解决 js 代码安全问题,在现代前端开发过程中,我们最常用的一种可以降低源代码可读性的方法就是使用代码混淆

  • 通常意义上的代码混淆可以压缩原始 ASCII 代码的体积并将其中的诸如:变量、常量名用简短的毫无意义的标识符进行代替,这一步可以简单的理解为去语义化。

  • 主流的混淆工具:

  • 以下使用 jshaman 工具免费版来演示 js 代码通过混淆后的效果

源代码:

function get_copyright() {
    var domain = 'jshaman.com'
    var from_year = 2017
    var copyright =
        '(c)' + from_year + '-' + new Date().getFullYear() + ',' + domain
    return copyright
}
console.log(get_copyright())
1
2
3
4
5
6
7
8

混淆后的代码:

/_Obfuscated by JShaman.com_/ function get_copyright() {
var \_0x1af084 = 'jshaman.com'
var \_0x456324 = 0xa645f ^ 0xa63be
var \_0x40d314 =
'(c)' + \_0x456324 + '-' + new Date()['getFullYear']() + ',' + \_0x1af084
return \_0x40d314
}
console['log'](<get_copyright()>)
1
2
3
4
5
6
7
8

# 工程化

  • 现在的前端开发项目大部分都已经是工程化项目,即用 Webpack 或者 Vite 作为构建工具进行开发和打包,在打包工具中其实已经有内置了 UglifyJS 等压缩混淆工具,所以在大部分的项目中已经自带了 混淆 功能,可能有的项目并没有开启而已,但是压缩效果是有的

# 小程序

# 压缩混淆

  • 在小程序中也有类似和 UglifyJS 的工具,在早些时候这个选项的名称也是叫 自动压缩混淆,不过 22 年开始,还是 21 年下旬的时候这个选项就被干掉了,变成了 上传代码时自动压缩脚本文件,但是他们的效果是一样的,都是简单混淆的压缩功能

20230924-1 20230924-2

# 代码加固

  • 小程序的代码加固功能也是使用字符串加密、属性加密、调用转换、代码混淆等操作进行处理代码,感觉像是把原来的选项配置中的 自动压缩混淆 单独抽了出来,不过比较麻烦的是需要在开发者工具上安装 devtool-code-obfuscation 扩展,上传时进行混淆

  • 代码加固和上传时进行代码保护的区别

20230924-3

  • 代码加固不能和 ci 一起使用,必须使用开发者工具使用

20230924-4

  • 那如何查看加固后的源码是啥样的呢?经过询问微信官方人员得出的结论是看不到!!!但是我又想验证加固到底有没有效果,于是我通过 node 命令反编译小程序的 wxapkg 的安装包得到了小程序发布的源码,通过对比有加固和没加固的代码发现确实有区别

20230924-5 20230924-6

同一个文件,加固后的文件大小会增大,并且会带有 DEBUG 的字样(官方说明是用于排错用的)

小程序代码加固文档 (opens new window)

如何通过 node 命令反编译 wxapkg 安装包的流程可以参考这篇文章 (opens new window)

  • 在验证有实际的加固效果后,那我们应该如何使用呢?说到这里可能大家会有个疑问,不就是在开发者工具中安装 devtool-code-obfuscation 扩展,然后配置 code_obfuscation_config.json 文件,然后点击上传再点击加固吗?实际上的使用流程确实是这样的,因为现在使用的是 uni-app 进行小程序开发,当我们运行或发行时会发现,我们代码加固的配置文件即 code_obfuscation_config.json 不会随着运行或发行放到 dist 目录下,这样子我们就需要每次都手动复制过去或者重新生成配置文件,为了解决此问题,我们可以通过 CopyWebpackPlugin 来帮我们自动复制,具体使用方式如下:

    • 在 vue.config.js 中进行配置,前提是 code_obfuscation_config.json 文件放在 src 目录下,具体根据场景自行修改路径
    const path = require('path')
    const CopyWebpackPlugin = require('copy-webpack-plugin') //最新版本 copy-webpack-plugin 插件暂不兼容,推荐 v5.0.0
    
    module.exports = {
        configureWebpack: {
            plugins: [
                new CopyWebpackPlugin([
                    {
                        from: path.join(
                            __dirname,
                            'src/code_obfuscation_config.json'
                        ),
                        to: path.join(
                            __dirname,
                            'dist',
                            process.env.NODE_ENV === 'production'
                                ? 'build'
                                : 'dev',
                            process.env.UNI_PLATFORM,
                            '/'
                        )
                    }
                ])
            ]
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

# 总结

  • 常用的安全策略是压缩混淆

  • 大部分工程化项目和小程序都自带压缩混淆

  • 小程序可以更进一步混淆使用代码加固(使用不方便)

# 参考文献

作者:chenjie
链接:https://webchenjie.cn
来源:ChenJieBlog

Last Updated: 2024/6/11 14:20:38
    飘向北方
    那吾克热-NW,尤长靖