在Python中安全存储与获取Windows认证API的服务账号密码
兄弟,我太懂你的感受了——在C#里用Directory Services搞Windows身份认证,完全不用在代码或配置里写密码,爽得一批。但Python这边确实没那么省心,尤其是服务账号的密码,绝对不能瞎存。下面给你几个生产环境常用的安全方案,都是经过验证的:
1. 用Windows自带的凭据管理器(最适配Windows环境)
这绝对是首选!Windows Credential Manager是系统级的安全存储,自带加密,而且不同用户账户之间隔离,不用担心密码泄露。你可以用keyring库来便捷操作它:
- 先安装依赖:
pip install keyring requests_ntlm - 存储密码(只需要运行一次,之后就不用管了):
import keyring # 第一个参数是凭据的自定义名称(方便识别),第二个是服务账号用户名,第三个是密码 keyring.set_password("MyInternalAPI", "domain\\service_user", "your_secure_password") - 调用API时获取密码:
import keyring from requests_ntlm import HttpNtlmAuth import requests username = "domain\\service_user" password = keyring.get_password("MyInternalAPI", username) response = requests.get("https://your-api-url.com", auth=HttpNtlmAuth(username, password))
注意:运行Python程序的账户(比如你部署的Windows服务账户)必须有权限访问这个存储的凭据,所以存储密码的时候要用同一个账户操作,或者在凭据管理器里手动设置权限。
2. 环境变量(适合跨平台/容器场景)
如果你的服务需要跨平台部署,或者用容器运行,把密码放在环境变量里是个不错的选择,避免密码出现在代码或配置文件中:
- 在Windows里设置环境变量:
- 临时生效(cmd):
set SERVICE_ACCOUNT_PASSWORD=your_secure_password - 永久生效:用
setx SERVICE_ACCOUNT_PASSWORD "your_secure_password",或者在系统属性的环境变量面板里配置,也可以在Windows服务的启动参数里添加。
- 临时生效(cmd):
- 代码中获取密码:
import os from requests_ntlm import HttpNtlmAuth import requests username = "domain\\service_user" password = os.getenv("SERVICE_ACCOUNT_PASSWORD") response = requests.get("https://your-api-url.com", auth=HttpNtlmAuth(username, password))
这种方式的好处是密码不落地,但要注意如果进程被恶意注入,可能会读取到环境变量,不过比明文存储安全太多。
3. 加密配置文件(自定义加密存储)
如果必须把密码存在文件里,绝对不能明文!可以用cryptography库做对称加密:
- 安装依赖:
pip install cryptography requests_ntlm - 生成加密密钥(只做一次,密钥要单独安全存储,比如放在只有服务账户能访问的路径):
from cryptography.fernet import Fernet # 生成密钥 key = Fernet.generate_key() # 保存密钥到文件(注意这个文件权限要设为只有服务账户可读) with open("api_key.key", "wb") as key_file: key_file.write(key) - 加密密码并保存:
from cryptography.fernet import Fernet # 读取密钥 with open("api_key.key", "rb") as key_file: key = key_file.read() fernet = Fernet(key) # 加密密码 encrypted_password = fernet.encrypt(b"your_secure_password") # 保存加密后的密码 with open("encrypted_pwd.txt", "wb") as pwd_file: pwd_file.write(encrypted_password) - 调用API时解密获取密码:
from cryptography.fernet import Fernet from requests_ntlm import HttpNtlmAuth import requests # 读取密钥 with open("api_key.key", "rb") as key_file: key = key_file.read() fernet = Fernet(key) # 读取加密后的密码并解密 with open("encrypted_pwd.txt", "rb") as pwd_file: encrypted_password = pwd_file.read() password = fernet.decrypt(encrypted_password).decode() username = "domain\\service_user" response = requests.get("https://your-api-url.com", auth=HttpNtlmAuth(username, password))
关键是密钥要和密码文件分开存,权限严格控制,只有运行程序的账户能访问。
4. 直接使用服务账户身份(无需密码,最省心)
如果你的Python程序是作为Windows服务运行的,而且服务本身就是用目标服务账户启动的,那完全可以不用密码!用requests-negotiate-sspi库直接利用当前进程的Windows身份认证,和C#的Directory Services原理一模一样:
- 安装依赖:
pip install requests-negotiate-sspi - 调用API:
import requests from requests_negotiate_sspi import HttpNegotiateAuth response = requests.get("https://your-api-url.com", auth=HttpNegotiateAuth())
这个方案最爽,完全不用处理密码,前提是程序运行的账户有访问API的权限,和你在C#里的使用方式完全对齐。
总结一下,优先推荐Windows凭据管理器或者直接使用服务账户身份,这两个方案最安全也最贴合Windows环境,不用自己折腾加密逻辑。如果跨平台的话,环境变量是不错的选择。
内容的提问来源于stack exchange,提问作者Kevin K.




