近期有一个Vue+Java+Docker项目中需要加密Python脚本的需求,调研后决定采用Cython。
使用Cython编译为二进制
步骤:
- 安装Cython:
pip install cython
- 创建setup.py:
from distutils.core import setup
from Cython.Build import cythonizesetup(ext_modules=cythonize("your_script.py"))
- 编译:
python setup.py build_ext --inplace
使用Cython加密多层目录中的Python脚本方案
针对多目录Python项目,下面提供了一个完整的Cython加密方案,包括批量处理脚本和Docker集成方法。
1. 项目结构准备
假设您的项目结构如下:
project/
├── scripts/
│ ├── module1/
│ │ ├── __init__.py
│ │ ├── utils.py
│ │ └── processor.py
│ ├── module2/
│ │ ├── __init__.py
│ │ └── analyzer.py
│ └── main.py
├── run.sh
└── Dockerfile
2. 批量加密脚本
创建build_cython.py
脚本来自动处理多目录加密:
import os
import glob
from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extensiondef scan_python_files(base_path):py_files = []for root, _, _ in os.walk(base_path):py_files.extend(glob.glob(os.path.join(root, "*.py")))return [f for f in py_files if not f.endswith('__init__.py')]def create_extensions(py_files):extensions = []for py_file in py_files:module_path = py_file.replace('.py', '').replace('/', '.')extensions.append(Extension(module_path, [py_file]))return extensionsif __name__ == "__main__":base_dir = "scripts" # 您的Python脚本目录py_files = scan_python_files(base_dir)extensions = create_extensions(py_files)setup(ext_modules=cythonize(extensions,compiler_directives={'language_level': "3",'always_allow_keywords': True},build_dir="build"))# 生成后的.so文件会保留原始目录结构
3. 构建和清理脚本
创建build.sh
脚本:
#!/bin/bash# 1. 安装依赖
pip install cython# 2. 编译Python文件
python build_cython.py build_ext --inplace# 3. 清理中间文件
find . -name "*.py" ! -name "__init__.py" ! -name "setup.py" -type f -delete
find . -name "*.c" -type f -delete
rm -rf build# 4. 修改权限
find . -name "*.so" -exec chmod 755 {} \;
4. Dockerfile集成
# 构建阶段
FROM python:3.9-slim as builderWORKDIR /app
COPY . .RUN apt-get update && \apt-get install -y gcc python3-dev && \pip install cython && \chmod +x build.sh && \./build.sh# 运行阶段
FROM python:3.9-slimWORKDIR /app
COPY --from=builder /app /app# 确保.so文件有执行权限
RUN find /app -name "*.so" -exec chmod 755 {} \; && \# 删除可能残留的.py文件find /app -name "*.py" -type f -delete && \# 安装运行时依赖pip install -r requirements.txt# 确保shell脚本可以执行
RUN chmod +x run.shCMD ["./run.sh"]
5. Shell脚本调用适配
修改您的run.sh
,确保它能找到.so文件而不是.py文件:
#!/bin/bash# 原来的调用方式可能是: python scripts/main.py
# 修改为:
PYTHONPATH=/app python -c "from scripts import main; main.main()"
6. 特殊处理
-
__init__.py
处理:- 保留目录中的
__init__.py
文件 - 确保它们为空或只包含必要导入
- 保留目录中的
-
动态导入问题:
如果有动态导入(如importlib.import_module
),需要预先生成所有可能的.so文件 -
第三方依赖:
确保在Docker中安装了所有Python依赖
7. 验证步骤
-
本地测试:
./build.sh python -c "from scripts.module1.processor import some_function; some_function()"
-
Docker测试:
docker build -t py-encrypted . docker run py-encrypted
注意事项
-
调试困难:加密后难以调试,建议保留开发环境的未加密副本
-
版本兼容性:生成的.so文件与Python版本和操作系统相关,确保构建和运行环境一致
-
性能影响:首次加载.so文件可能比.py稍慢,但运行时性能更好
-
不完全加密:Cython并非完全不可逆向,但对大多数场景已足够安全
这个方案将您的所有Python脚本(除了__init__.py
)转换为.so二进制文件,同时保持原始目录结构,确保您的shell脚本可以继续正常工作。