为确保我们的Python源码的安全,可以考虑使用加密工具加密。如果客户的运行环境不是专业的运行环境,没有安装Python或者Docker等,可以选择把加密后的程序再打包发布为一个可执行文件,提供给客户。
一.加密工具:PyArmor
Pyarmor 是一个用于加密和保护 Python 脚本的工具。它能够在运行时刻保护 Python 脚本代码不被泄露,设置加密后脚本的使用期限,绑定加密脚本到硬盘、网卡等硬件设备。
1.功能特点
- 无缝替换: 加密后的脚本依然是一个有效的 .py 文件,在大多数情况下可以直接替换原来的 .py 脚本,而不影响脚本的使用。
- 均衡加密: 提供了丰富的加密选项来平衡安全性和性能,能够满足大多数应用对安全性和性能的要求。
- 不可逆加密: 能够直接重命名源代码中的函数,类,方法,变量和参数。
- 转换成为 C 代码: 能够把模块中部分函数转换成为 C 代码,然后使用高优化选项直接编译 C 代码为机器指令来保护 Python 函数
- 限制加密脚本的使用范围: 可以绑定加密脚本到指定的设备或者设置加密脚本的有效期
- Themida 保护: 使用 Themida 保护加密脚本(仅 Windows 平台可用)
2.安装
#直接安装
$ pip install pyarmor
#更新版本
$ pip install --upgrade pyarmor
#另外还有一个图形界面的包,需要的话可以安装:
$ pip install pyarmor-webui
#安装后,可以直接运行如下命令查看版本,检查是否安装成功
$ pyarmor --version
3.加密
8.0之前的版本使用如下命令加密(假设你的主入口文件为:your_main.py):
$ pyarmor obfuscate your_main.py
8.0以后的版本使用上述命令会提示:
Pyarmor 8.0+ has only 3 commands: gen, reg, cfg
Please replace `pyarmor` with `pyarmor-7` to run old commands
需要使用如下命令(我安装的版本是 v8.5.10):
$ pyarmor gen your_main.py
PyArmor 会加密 your_main.py 和相同目录下面的所有 *.py 文件:
- 创建输出子目录 dist
- 生成加密的主脚本 your_main.py 保存在输出目录 dist
- 加密相同目录下其他所有 *.py 文件,保存到输出目录 dist
- 生成运行加密脚本所需要的全部辅助文件,保存到输出目录 dist
除了加密脚本之外,可以看到还有另外一个目录 pyarmor_runtime_000000 ,这是运行加密脚本所依赖的一个 Python 包 。
4.一步到位:加密并打包
pyarmor gen -O dist_main --pack onefile your_main.py
-O 指定了输出目标文件到目录dist_main
–pack 指定生成exe文件及生成模式(onefile:单个文件)
这是个一步到位的命令,使用该命令加密并打包,就不用使用PyInstaller再单独打包了
参考博客: Python工程加密打包(基于pyinstaller 6.11.1和pyarmor 9.0.5)(202411)
二.打包工具:PyInstaller
1.简介
PyInstaller可以将Python应用程序及其所有依赖项捆绑到一个包中。用户可以在不安装Python解释器或任何模块的情况下运行打包的应用程序。PyInstaller支持Python 3.8及更新版本,并正确地捆绑了许多主要的Python包,如numpy、matplotlib、PyQt、wxPython等。
PyInstaller针对Windows、MacOS X和Linux进行了测试。然而,它不是一个交叉编译器;要制作Windows应用程序,您可以在Windows上运行PyInstaller。要制作Linux应用程序,请在Linux上运行它。要制作MacOS应用程序,请在MacOS上运行它。
2.安装
#直接安装
$ pip install pyinstaller
#更新版本
$ pip install --upgrade pyinstaller
#检查是否安装成功
$ pyinstaller --version
3.打包
$ pyinstaller your_main.py
#或者加入 -F 参数直接指定为:打包成一个可执行文件
$ pyinstaller -F your_main.py
PyInstaller分析your_main.py并:
- 将 your_main.spec 写入与脚本相同的文件夹中。
- 如果脚本不存在,则在与脚本相同的文件夹中创建文件夹生成。
- 在生成文件夹中写入一些日志文件和工作文件。
- 如果脚本不存在,则在与脚本相同的文件夹中创建文件夹dist。
- 将your_main可执行文件文件夹写入dist文件夹。
4.运行报错
打包后,在产生的dist文件夹中就是你的可执行文件,尝试执行它,可能会报错:
Traceback (most recent call last):
File "<frozen __main__>", line 3, in <module>
File "<frozen your_main>", line 7, in <module>
ModuleNotFoundError: No module named 'requests'
分析:
错误信息提示缺少模块requests,或者你的提示是缺少其他的模块。
原因是打包时,没有将你引用的模块一起打进可执行文件中。此时我们需要使用那个产生的your_main.spec来配置一些信息。
5.spec文件中指定依赖模块
your_main.spec 原始内容如下:
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['your_main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='your_main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
在hiddenimports中加入你的项目所依赖的模块(报错信息中缺少的模块),我的项目中依赖了如下模块:
hiddenimports=['requests','openpyxl','smtplib','email.mime', 'email.mime.multipart', 'email.mime.text'],
修改了hiddenimports之后,使用如下命令重新打包:
$ pyinstaller your_main.spec
可执行文件成功运行~
至此,项目代码已经加密,并且打包为一个可执行文件。