将python源程序编译为pyc或pyo字节码程序

时间:2022-01-05 17:09:35
为了提高自己搭建的Django站点的安全性,将加密后的数据库连接信息以及加密使用的信息单独存放在了一个配置文件中,之后写了一个中间层来解密配置文件中的密文并用于站点应用连接数据库。虽然这样一种安全方式很初级,但起码比明文存放密码等敏感信息要好的多。

现在面临另外一个问题,因为最终密文形式的密码还是需要解密后才能使用的,上边提到的用于解密配置文件中的密文的中间层正是用于此目的。若恶意用户获取到了相关文件,很容易根据文件中的代码推测出加密使用的算法,也很容易获取的明文的密码,因此现在需要一种方式将python源代码转换成不能被“小人”轻易读取的文件形式。

怎么转换呢?其实通过将python源程序.py文件编译为字节码文件.pyc或.pyo就可以很好的达到上述目的(尽管这仍有可能被恶意着反编译为.py源文件,但至少算是有加强了一层防护,是无意的“君子”不至于这么轻松获取密码。)

那么该如何编译python源程序呢?

可以有多重形式:
python -m py_compile file.py #把单个.py文件编译为字节码文件
python -m py_compile /path/to/src/ #批量生成字节码文件,/path/to/src/是包含.py文件名的路径
python -m compileall file.py #把单个.py文件编译为字节码文件
python -m compileall /path/to/src/ #批量生成字节码文件,/path/to/src/是包含.py文件名的路径

或者:
python -O -m py_compile file.py
python -O -m py_compile /path/to/src/
python -O -m compileall file.py
python -O -m compileall /path/to/src/

或者
python -OO -m py_compile file.py
python -OO -m py_compile /path/to/src/
python -OO -m compileall file.py
python -OO -m compileall /path/to/src/

或者通过脚本来编译:
import py_compile
py_compile.compile('file.py')

import compileall
compileall.compile_file('file.py')

import compileall
compileall.compile_dir('/path/to/src/')
compileall.compile_path()

具体参数:
    compile(file, cfile=None, dfile=None, doraise=False)
        Byte-compile one Python source file to Python bytecode.
        
        Arguments:
        
        file:    source filename
        cfile:   target filename; defaults to source with 'c' or 'o' appended
                 ('c' normally, 'o' in optimizing mode, giving .pyc or .pyo)
        dfile:   purported filename; defaults to source (this is the filename
                 that will show up in error messages)
        doraise: flag indicating whether or not an exception should be
                 raised when a compile error is found. If an exception
                 occurs and this flag is set to False, a string
                 indicating the nature of the exception will be printed,
                 and the function will return to the caller. If an
                 exception occurs and this flag is set to True, a
                 PyCompileError exception will be raised.


    compile_dir(dir, maxlevels=10, ddir=None, force=0, rx=None, quiet=0)
        Byte-compile all modules in the given directory tree.
        
        Arguments (only dir is required):
        
        dir:       the directory to byte-compile
        maxlevels: maximum recursion level (default 10)
        ddir:      the directory that will be prepended to the path to the
                   file as it is compiled into each byte-code file.
        force:     if 1, force compilation, even if timestamps are up-to-date
        quiet:     if 1, be quiet during compilation
    
    compile_file(fullname, ddir=None, force=0, rx=None, quiet=0)
        Byte-compile one file.
        
        Arguments (only fullname is required):
        
        fullname:  the file to byte-compile
        ddir:      if given, the directory name compiled in to the
                   byte-code file.
        force:     if 1, force compilation, even if timestamps are up-to-date
        quiet:     if 1, be quiet during compilation
    
    compile_path(skip_curdir=1, maxlevels=0, force=0, quiet=0)
        Byte-compile all module on sys.path.
        
        Arguments (all optional):
        
        skip_curdir: if true, skip current directory (default true)
        maxlevels:   max recursion level (default 0)
        force: as for compile_dir() (default 0)
        quiet: as for compile_dir() (default 0)

注解:
-m参数相当于脚本中的import,这里的-m py_compile 相当于上面的 import py_compile,也即把后边跟随的库模块当做脚本运行。这样生成的字节码文件后缀名为.pyc
-O参数表明要生成更加紧凑的优化后的字节码,-OO会进一步移除-O选项生成的优化后的字节码文件中的文档字符串。这样生成的字节码文件后缀名为.pyo,对于.pyo文件可以通过 python命令加-O参数执行导入了该模块的python程序来调用。
需注意的是,不同版本编译后的pyc文件是不同的,比如2.5编译的pyc文件2.4版本的python是无法执行的。