這聽起來像一個非常糟糕的主意。您可以加密登錄名和密碼,但任何有權訪問主密碼的人都可以訪問所有單個登錄名。這意味着你可以保證個人登錄不會長久保密,如果他們泄露了,你將不得不改變他們。
更好的解決方案是將每個用戶的應用程序自己的登錄名分配給每臺服務器。然後,您的應用程序可以爲其訪問的每臺服務器使用相同的登錄名/密碼,並且根本不需要將密碼存儲在應用程序中。如果一個用戶的密碼被泄露,您只需更改其所有登錄名的密碼,而其他用戶不會受到影響。
或者將所有登錄路由通過單個服務器代理:代理可以位於安全系統上,因此,每個用戶都不會接近任何基礎帳戶,並且可以保護個人用戶帳戶對代理的訪問。
我挖掘了一些舊的代碼,並從我稱之爲'passwordcache.py'的模塊中提出了以下內容。看看是否有幫助:
"""Password Cache
This module provides a portable interface for caching passwords.
Operations:
Store a password.
Retrieve a password (which may prompt for a password if it needs it).
Test whether or not we have a password stored.
Clear a stored password.
Passwords are identified by a combination key app/service/user.
"""
import sys, os, random, hashlib
random.seed() # Init random number generator from other random source or system time
class PasswordCacheBase(object):
"""Base class for common functionality between different platform implementations"""
def __init__(self, application=None):
"""PasswordCache(application)
Creates a new store for passwords (or opens an existing one).
The application name may be any string, but defaults to the script name.
"""
if application is None:
self.application = os.path.basename(sys.argv[0])
else:
self.application = application
def get(self, service, user, getpass=None, cache=False):
"""Retrieve a password from the store"""
raise NotImplementedError()
def set(self, service, user, password):
"""Save a password in the store"""
raise NotImplementedError()
def exists(self, service, user):
"""Check whether a password exists"""
try:
pwd = self.get(service, user)
except KeyError:
return False
return True
def clear(self, service, user):
raise NotImplementedError()
def salt(self, service, user):
"""Get a salt value to help prevent encryption collisions. The salt string is 16 bytes long."""
salt = hashlib.md5("%r|%s|%s|%s" % (random.random(), self.application, service, user)).digest()
return salt
if sys.platform=="win32":
"""Interface to Windows data protection api.
Based on code from:
http://osdir.com/ml/python.ctypes/2003-07/msg00091.html
"""
from ctypes import *
from ctypes.wintypes import DWORD
import _winreg
import cPickle as pickle
LocalFree = windll.kernel32.LocalFree
# Note that CopyMemory is defined in term of memcpy:
memcpy = cdll.msvcrt.memcpy
CryptProtectData = windll.crypt32.CryptProtectData
CryptUnprotectData = windll.crypt32.CryptUnprotectData
# See http://msdn.microsoft.com/architecture/application/default.aspx?pull=/library/en-us/dnnetsec/html/SecNetHT07.asp
CRYPTPROTECT_UI_FORBIDDEN = 0x01
class DATA_BLOB(Structure):
# See d:\vc98\Include\WINCRYPT.H
# This will not work
# _fields_ = [("cbData", DWORD), ("pbData", c_char_p)]
# because accessing pbData will create a new Python string which is
# null terminated.
_fields_ = [("cbData", DWORD), ("pbData", POINTER(c_char))]
class PasswordCache(PasswordCacheBase):
def set(self, service, user, password):
"""Save a password in the store"""
salt = self.salt(service, user)
encrypted = self.Win32CryptProtectData(
'%s' % password, salt)
key = self._get_regkey()
try:
data = self._get_registrydata(key)
data[service, user] = (salt, encrypted)
self._put_registrydata(key, data)
finally:
key.Close()
def get(self, service, user, getpass=None, cache=False):
data = self._get_registrydata()
try:
salt, encrypted = data[service, user]
decrypted = self.Win32CryptUnprotectData(encrypted, salt)
except KeyError:
if getpass is not None:
password = getpass()
if cache:
self.set(service, user, password)
return password
raise
return decrypted
def clear(self, service=None, user=None):
key = self._get_regkey()
try:
data = self._get_registrydata(key)
if service is None:
if user is None:
data = {}
else:
for (s,u) in data.keys():
if u==user:
del data[s,u]
else:
if user is None:
for (s,u) in data.keys():
if s==service:
del data[s,u]
else:
if (service,user) in data:
del data[service,user]
self._put_registrydata(key, data)
finally:
key.Close()
def _get_regkey(self):
return _winreg.CreateKey(
_winreg.HKEY_CURRENT_USER,
r'Software\Python\Passwords')
def _get_registrydata(self, regkey=None):
if regkey is None:
key = self._get_regkey()
try:
return self._get_registrydata(key)
finally:
key.Close()
try:
current = _winreg.QueryValueEx(regkey, self.application)[0]
data = pickle.loads(current.decode('base64'))
except WindowsError:
data = {}
return data
def _put_registrydata(self, regkey, data):
pickled = pickle.dumps(data)
_winreg.SetValueEx(regkey,
self.application,
None,
_winreg.REG_SZ,
pickled.encode('base64'))
def getData(self, blobOut):
cbData = int(blobOut.cbData)
pbData = blobOut.pbData
buffer = c_buffer(cbData)
memcpy(buffer, pbData, cbData)
LocalFree(pbData);
return buffer.raw
def Win32CryptProtectData(self, plainText, entropy):
bufferIn = c_buffer(plainText, len(plainText))
blobIn = DATA_BLOB(len(plainText), bufferIn)
bufferEntropy = c_buffer(entropy, len(entropy))
blobEntropy = DATA_BLOB(len(entropy), bufferEntropy)
blobOut = DATA_BLOB()
# The CryptProtectData function performs encryption on the data
# in a DATA_BLOB structure.
# BOOL WINAPI CryptProtectData(
# DATA_BLOB* pDataIn,
# LPCWSTR szDataDescr,
# DATA_BLOB* pOptionalEntropy,
# PVOID pvReserved,
# CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
# DWORD dwFlags,
# DATA_BLOB* pDataOut
if CryptProtectData(byref(blobIn), u"win32crypto.py", byref(blobEntropy),
None, None, CRYPTPROTECT_UI_FORBIDDEN, byref(blobOut)):
return self.getData(blobOut)
else:
return None
def Win32CryptUnprotectData(self, cipherText, entropy):
bufferIn = c_buffer(cipherText, len(cipherText))
blobIn = DATA_BLOB(len(cipherText), bufferIn)
bufferEntropy = c_buffer(entropy, len(entropy))
blobEntropy = DATA_BLOB(len(entropy), bufferEntropy)
blobOut = DATA_BLOB()
if CryptUnprotectData(byref(blobIn), None, byref(blobEntropy), None, None,
CRYPTPROTECT_UI_FORBIDDEN, byref(blobOut)):
return self.getData(blobOut)
else:
return None
else: # Not Windows, try for gnome-keyring
import gtk # ensure that the application name is correctly set
import gnomekeyring as gkey
class Keyring(object):
def __init__(self, name, server, protocol):
self._name = name
self._server = server
self._protocol = protocol
self._keyring = k = gkey.get_default_keyring_sync()
import pdb; pdb.set_trace()
print dir(k)
class PasswordCache(PasswordCacheBase):
def __init__(self, application=None):
PasswordCacheBase.__init__(self, application)
self._keyring = gkey.get_default_keyring_sync()
def set(self, service, user, password):
"""Save a password in the store"""
attrs = {
"application": self.application,
"user": user,
"server": service,
}
gkey.item_create_sync(self._keyring,
gkey.ITEM_NETWORK_PASSWORD, self.application, attrs, password, True)
def get(self, service, user, getpass=None, cache=False):
attrs = {
"application": self.application,
"user": user,
"server": service}
try:
items = gkey.find_items_sync(gkey.ITEM_NETWORK_PASSWORD, attrs)
except gkey.NoMatchError:
if getpass is not None:
password = getpass()
if cache:
self.set(service, user, password)
return password
raise KeyError((service,user))
return items[0].secret
def clear(self, service=None, user=None):
attrs = {'application':self.application}
if user is not None:
attrs["user"] = user
if service is not None:
attrs["server"] = service
try:
items = gkey.find_items_sync(gkey.ITEM_NETWORK_PASSWORD, attrs)
except gkey.NoMatchError:
return
for item in items:
gkey.item_delete_sync(self._keyring, item.item_id)
感謝您的回答。但是,在這兩種解決方案中,如果您丟失登錄名/密碼,則必須在所有服務器上更改它們。 其次,出於安全原因,我不想在所有服務器上使用相同的密碼。 我必須添加一些細節: 1)我應該是唯一使用該應用程序的人。 2)目前,所有密碼都存儲在應用程序中。我現在要刪除它們,以便如果有人使用我的電腦,他將不會訪問服務器/計算機。 3)每臺服務器都有自己的登錄/密碼配置。 感謝您的幫助! 此致敬禮。 – Korchkidu 2010-07-02 08:57:46
好吧,所以你是唯一的用戶,但你想保護你的應用程序使用的密碼。你能否澄清你正在使用的系統:Windows還是Linux。如果Windows那麼有win32 api調用,它允許你存儲只能由你訪問的加密數據。您不需要主密碼,因爲數據在您登錄時可以訪問,但在其他人登錄時不會訪問。如果是Linux,那麼你可以使用gnome-keyring。 – Duncan 2010-07-02 11:46:26
嗨,我更新了這個問題。但是,是的,我只是想知道它將安裝在幾個不同的系統上,以保護應用程序。 – Korchkidu 2010-07-13 05:35:15