Python脚本隐藏凭据最优方法及PyInstaller打包安全性问询
嘿,这个问题问到点子上了——明文存储凭据绝对是安全大忌,我来给你分享几个生产环境里常用的安全方案,顺便解答你关于PyInstaller的疑问:
一、Python脚本中隐藏凭据的最佳方法
1. 使用环境变量(最便捷的无代码硬编码方案)
把服务器地址和密码存在系统环境变量里,脚本通过os.getenv()读取,完全避免硬编码。
示例代码:
import paramiko import os # 从环境变量读取凭据 my_server = os.getenv('SSH_TARGET_SERVER') my_password = os.getenv('SSH_ROOT_PASSWORD') ssh = paramiko.client.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh.connect(my_server, username='root', password=my_password) except paramiko.SSHException: print("Connection Failed") quit()
- 设置方式:Windows用
setx SSH_TARGET_SERVER "myserver",Linux/macOS用export SSH_TARGET_SERVER=myserver(永久生效需要写入bashrc/zshrc或系统配置文件)。
2. 加密配置文件(适合需要持久化存储的场景)
如果必须把凭据存在文件里,一定要加密,不能用明文。推荐用cryptography库实现对称加密:
第一步:生成密钥并加密凭据(只执行一次)
from cryptography.fernet import Fernet # 生成加密密钥,务必妥善保管(别和脚本/打包后的exe放一起) key = Fernet.generate_key() with open('secret.key', 'wb') as key_file: key_file.write(key) # 加密服务器地址和密码 cipher = Fernet(key) encrypted_server = cipher.encrypt(b'myserver') encrypted_password = cipher.encrypt(b'mysecret') # 保存加密后的内容 with open('credentials.enc', 'wb') as enc_file: enc_file.write(encrypted_server + b'\n' + encrypted_password)
第二步:脚本中解密读取凭据
import paramiko from cryptography.fernet import Fernet # 加载密钥(注意密钥要单独存放,比如加密存储在本地或者由用户手动输入) with open('secret.key', 'rb') as key_file: key = key_file.read() cipher = Fernet(key) # 读取并解密 with open('credentials.enc', 'rb') as enc_file: encrypted_server = enc_file.readline().strip() encrypted_password = enc_file.readline().strip() my_server = cipher.decrypt(encrypted_server).decode() my_password = cipher.decrypt(encrypted_password).decode() # 后续连接逻辑不变 ssh = paramiko.client.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh.connect(my_server, username='root', password=my_password) except paramiko.SSHException: print("Connection Failed") quit()
3. SSH密钥认证(最安全的SSH连接方式)
完全抛弃密码,用SSH密钥对认证:
- 生成本地密钥对(
ssh-keygen命令,可设置密钥密码); - 将公钥上传到服务器的
~/.ssh/authorized_keys文件中; - 脚本中用私钥连接:
import paramiko from getpass import getpass ssh = paramiko.client.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: # 如果私钥设置了密码,用getpass交互式输入,避免硬编码 passphrase = getpass("Enter private key passphrase (if set): ") ssh.connect( 'myserver', username='root', key_filename='/path/to/your/private_key', passphrase=passphrase ) except paramiko.SSHException: print("Connection Failed") quit()
这种方式就算私钥泄露,没有密码也无法使用,安全性拉满。
4. 交互式输入(适合手动触发的脚本)
如果脚本不需要自动化运行,用getpass模块让用户手动输入凭据,完全不存储:
import paramiko from getpass import getpass my_server = input("Enter target server address: ") my_password = getpass("Enter root password: ") ssh = paramiko.client.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh.connect(my_server, username='root', password=my_password) except paramiko.SSHException: print("Connection Failed") quit()
二、PyInstaller打包后是否能被反汇编拿到明文?
答案是肯定的。PyInstaller只是把Python脚本、依赖库和解释器打包成一个可执行文件,内部包含的是编译后的Python字节码(.pyc格式)。而字节码非常容易被反编译回近似原始的Python代码,甚至用strings命令直接扫描exe文件,就能提取出硬编码的明文凭据。
所以绝对不能把明文凭据硬编码在脚本里再打包,一定要用上面提到的安全方案替代。
内容的提问来源于stack exchange,提问作者DDBE




