我有一个python脚本正在创建ODBC连接。ODBC连接是使用连接字符串生成的。在此连接字符串中,我必须包含此连接的用户名和密码。
有没有一种简便的方法来隐藏文件中的此密码(只是在我编辑文件时没人能读取该密码)?
我有一个python脚本正在创建ODBC连接。ODBC连接是使用连接字符串生成的。在此连接字符串中,我必须包含此连接的用户名和密码。
有没有一种简便的方法来隐藏文件中的此密码(只是在我编辑文件时没人能读取该密码)?
Answers:
Base64编码在标准库中,并且可以阻止肩膀冲浪者:
>>> import base64
>>> print(base64.b64encode("password".encode("utf-8")))
cGFzc3dvcmQ=
>>> print(base64.b64decode("cGFzc3dvcmQ=").decode("utf-8"))
password
base64
比rot13
在这种情况下更好。相反,base64
它具有其典型特征(等号,...),因此比其他方法更易于检测。但是,任何混淆都没有实际好处。这个答案受到如此高度评价真的很不好。它只是给人一种错误的安全感……
base64
,最好rot13
使用Python标准库中的方法。
当您需要为远程登录指定密码时,Douglas F Shearer's是Unix中公认的解决方案。
您添加--password-from-file选项来指定路径并从文件中读取纯文本。
然后,该文件可以位于受操作系统保护的用户自己的区域中。它还允许不同的用户自动选择自己的文件。
对于不允许脚本用户知道的密码-您可以使用高级权限运行脚本,并让该root / admin用户拥有密码文件。
这是一个简单的方法:
尽管它容易受到py_to_pyc反编译器的攻击,但它应该比base64解码更加安全。
import peekabo
,密码可用peekaboo.password
(如果包含peekaboo.py password='secret'
)
如果您在Unix系统上工作,请利用标准Python库中的netrc模块。它从单独的文本文件(.netrc)中读取密码,该文件的格式在此处描述。
这是一个小用法示例:
import netrc
# Define which host in the .netrc file to use
HOST = 'mailcluster.loopia.se'
# Read from the .netrc file in your home directory
secrets = netrc.netrc()
username, account, password = secrets.authenticators( HOST )
print username, password
假设用户无法在运行时提供用户名和密码,最好的解决方案可能是单独的源文件,其中仅包含导入到您的主代码中的用户名和密码的变量初始化。仅在凭据更改时才需要编辑此文件。否则,如果您只担心具有平均记忆的冲浪者,那么base 64编码可能是最简单的解决方案。ROT13太容易手动解码,不区分大小写,并且在加密状态下保留了太多含义。在python脚本之外对您的密码和用户ID进行编码。让他在运行时对脚本进行解码以供使用。
为自动化任务提供脚本凭证始终是一个冒险的建议。您的脚本应具有其自己的凭据,并且所使用的帐户应完全不需要访问权限。至少密码应该是长且相当随机的。
base64是满足您简单需求的方法。无需导入任何内容:
>>> 'your string'.encode('base64')
'eW91ciBzdHJpbmc=\n'
>>> _.decode('base64')
'your string'
对于python3混淆,使用base64
方式有所不同:
import base64
base64.b64encode(b'PasswordStringAsStreamOfBytes')
导致
b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM='
注意非正式的字符串表示形式,实际的字符串用引号引起来
并解码回原始字符串
base64.b64decode(b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM=')
b'PasswordStringAsStreamOfBytes'
在需要字符串对象的地方使用此结果,可以翻译字节对象
repr = base64.b64decode(b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM=')
secret = repr.decode('utf-8')
print(secret)
有关python3如何处理字节(以及相应的字符串)的更多信息,请参见官方文档。
这是一个很常见的问题。通常,您能做的最好的就是
A)创建某种ceasar密码函数来进行编码/解码(但不是rot13)或
B)首选方法是在程序可及的范围内使用加密密钥对密码进行编码/解码。您可以在其中使用文件保护来保护访问密钥。
如果您的应用程序作为服务/守护程序(例如Web服务器)运行,则可以将密钥放入密码保护的密钥库中,并在服务启动过程中输入密码。管理员需要重新启动您的应用程序,但是您对配置密码的保护非常好。
更多本地化的方式,而不是将身份验证/密码/用户名转换为加密的详细信息。FTPLIB只是示例。“ pass.csv ”是csv文件名
将密码保存为CSV格式,如下所示:
用户名
用户密码
(无列标题)
读取CSV并将其保存到列表中。
使用列表元素作为认证详细信息。
完整代码。
import os
import ftplib
import csv
cred_detail = []
os.chdir("Folder where the csv file is stored")
for row in csv.reader(open("pass.csv","rb")):
cred_detail.append(row)
ftp = ftplib.FTP('server_name',cred_detail[0][0],cred_detail[1][0])
这是我的摘录。您基本上是将函数导入或复制到代码中。如果加密文件不存在,getCredentials将创建该加密文件并返回命令,updateCredential将更新。
import os
def getCredentials():
import base64
splitter='<PC+,DFS/-SHQ.R'
directory='C:\\PCT'
if not os.path.exists(directory):
os.makedirs(directory)
try:
with open(directory+'\\Credentials.txt', 'r') as file:
cred = file.read()
file.close()
except:
print('I could not file the credentials file. \nSo I dont keep asking you for your email and password everytime you run me, I will be saving an encrypted file at {}.\n'.format(directory))
lanid = base64.b64encode(bytes(input(' LanID: '), encoding='utf-8')).decode('utf-8')
email = base64.b64encode(bytes(input(' eMail: '), encoding='utf-8')).decode('utf-8')
password = base64.b64encode(bytes(input(' PassW: '), encoding='utf-8')).decode('utf-8')
cred = lanid+splitter+email+splitter+password
with open(directory+'\\Credentials.txt','w+') as file:
file.write(cred)
file.close()
return {'lanid':base64.b64decode(bytes(cred.split(splitter)[0], encoding='utf-8')).decode('utf-8'),
'email':base64.b64decode(bytes(cred.split(splitter)[1], encoding='utf-8')).decode('utf-8'),
'password':base64.b64decode(bytes(cred.split(splitter)[2], encoding='utf-8')).decode('utf-8')}
def updateCredentials():
import base64
splitter='<PC+,DFS/-SHQ.R'
directory='C:\\PCT'
if not os.path.exists(directory):
os.makedirs(directory)
print('I will be saving an encrypted file at {}.\n'.format(directory))
lanid = base64.b64encode(bytes(input(' LanID: '), encoding='utf-8')).decode('utf-8')
email = base64.b64encode(bytes(input(' eMail: '), encoding='utf-8')).decode('utf-8')
password = base64.b64encode(bytes(input(' PassW: '), encoding='utf-8')).decode('utf-8')
cred = lanid+splitter+email+splitter+password
with open(directory+'\\Credentials.txt','w+') as file:
file.write(cred)
file.close()
cred = getCredentials()
updateCredentials()
你知道坑吗?
https://pypi.python.org/pypi/pit(仅适用于py2(0.3版))
https://github.com/yoshiori/pit(它将在py3上运行(当前版本0.4))
test.py
from pit import Pit
config = Pit.get('section-name', {'require': {
'username': 'DEFAULT STRING',
'password': 'DEFAULT STRING',
}})
print(config)
跑:
$ python test.py
{'password': 'my-password', 'username': 'my-name'}
〜/ .pit / default.yml:
section-name:
password: my-password
username: my-name
/usr/lib/python3.7/site-packages/pit.py:93: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details. return yaml.load(open(Pit._config))
如果在Windows上运行,则可以考虑使用win32crypt库。它允许运行脚本的用户存储和检索受保护的数据(键,密码),因此,密码永远不会以明文或混淆格式存储在代码中。我不确定其他平台是否有等效的实现,因此如果严格使用win32crypt,您的代码将无法移植。
我相信可以在这里获得该模块:http : //timgolden.me.uk/pywin32-docs/win32crypt.html
我执行此操作的方法如下:
在python shell上:
>>> from cryptography.fernet import Fernet
>>> key = Fernet.generate_key()
>>> print(key)
b'B8XBLJDiroM3N2nCBuUlzPL06AmfV4XkPJ5OKsPZbC4='
>>> cipher = Fernet(key)
>>> password = "thepassword".encode('utf-8')
>>> token = cipher.encrypt(password)
>>> print(token)
b'gAAAAABe_TUP82q1zMR9SZw1LpawRLHjgNLdUOmW31RApwASzeo4qWSZ52ZBYpSrb1kUeXNFoX0tyhe7kWuudNs2Iy7vUwaY7Q=='
然后,使用以下代码创建一个模块:
from cryptography.fernet import Fernet
# you store the key and the token
key = b'B8XBLJDiroM3N2nCBuUlzPL06AmfV4XkPJ5OKsPZbC4='
token = b'gAAAAABe_TUP82q1zMR9SZw1LpawRLHjgNLdUOmW31RApwASzeo4qWSZ52ZBYpSrb1kUeXNFoX0tyhe7kWuudNs2Iy7vUwaY7Q=='
# create a cipher and decrypt when you need your password
cipher = Fernet(key)
mypassword = cipher.decrypt(token).decode('utf-8')
完成此操作后,您可以直接导入mypassword,也可以导入令牌和密码以根据需要进行解密。
显然,这种方法有一些缺点。如果某人同时拥有令牌和密钥(就像他们拥有脚本一样),则他们可以轻松解密。但是,它的确模糊不清,如果您编译代码(使用Nuitka之类的代码),则至少您的密码不会在十六进制编辑器中显示为纯文本。
您还可以考虑将密码存储在脚本外部并在运行时提供密码的可能性
例如fred.py
import os
username = 'fred'
password = os.environ.get('PASSWORD', '')
print(username, password)
可以像
$ PASSWORD=password123 python fred.py
fred password123
可以通过使用base64
(如上所述),在代码中使用不太明显的名称以及使实际密码与代码之间的距离进一步达到“通过模糊性实现安全性” 的目的。
如果代码位于存储库中,通常将机密存储在存储库之外很有用,因此可以将其添加到~/.bashrc
(或添加到Vault或启动脚本中,...)
export SURNAME=cGFzc3dvcmQxMjM=
并更改fred.py
为
import os
import base64
name = 'fred'
surname = base64.b64decode(os.environ.get('SURNAME', '')).decode('utf-8')
print(name, surname)
然后重新登录并
$ python fred.py
fred password123
在网上有几种用Python编写的ROT13实用程序-只是谷歌搜索它们。ROT13离线编码字符串,将其复制到源中,然后在传输点解码。
但这确实是薄弱的保护...