Cela semble être une très mauvaise idée. Vous pouvez crypter les connexions et les mots de passe, mais toute personne ayant accès au mot de passe principal aura alors accès à toutes les connexions individuelles. Cela signifie que vous pouvez garantir que les connexions individuelles ne resteront pas un secret pour longtemps et si elles fuient, vous devrez les changer tous.
Une meilleure solution serait de donner à chaque utilisateur de votre application son propre identifiant sur chacun de vos serveurs. Ensuite, votre application peut utiliser le même login/mot de passe pour chaque serveur auquel elle accède et le mot de passe n'a pas besoin d'être stocké dans l'application. Si le mot de passe d'un utilisateur est divulgué, vous changez simplement son mot de passe sur tous ses identifiants et les autres utilisateurs ne sont pas affectés. Vous pouvez également acheminer toutes les connexions via un proxy serveur unique: le proxy peut se trouver sur un système sécurisé, de sorte qu'aucun des utilisateurs n'approche des comptes sous-jacents et vous pouvez protéger l'accès au proxy par des comptes utilisateur individuels. Je ai creusé une partie de mon ancien code et suis venu avec ce qui suit d'un module que j'ai appelé «passwordcache.py». Voir si cela aide:
"""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)
Merci pour votre réponse. Cependant, dans les deux solutions, si vous perdez le login/mot de passe, vous devrez les changer sur tous les serveurs. Deuxièmement, pour des raisons de sécurité, je ne veux pas utiliser les mêmes mots de passe sur tous les serveurs. Je dois ajouter quelques détails: 1) Je suis censé être le seul à utiliser l'application. 2) Pour le moment, tous les mots de passe sont stockés dans l'application. Je veux maintenant les enlever de sorte que si quelqu'un utilise mon ordinateur, il n'accédera pas aux serveurs/ordinateurs. 3) Chaque serveur a sa propre configuration de connexion/mot de passe. Merci pour votre aide! Cordialement. – Korchkidu
Ok, donc vous êtes le seul utilisateur mais vous voulez protéger les mots de passe utilisés par votre application. Pouvez-vous clarifier le système que vous utilisez: Windows ou Linux. Si Windows alors il y a des appels api win32 qui vous permettent de stocker des données cryptées qui ne sont accessibles qu'à vous. Vous n'avez pas besoin d'un mot de passe principal car les données seront accessibles lorsque vous serez connecté mais pas lorsque quelqu'un d'autre sera connecté. Si Linux alors vous pouvez utiliser gnome-keyring de la même manière. – Duncan
Salut, j'ai mis à jour la question. Mais oui, je veux simplement protéger l'application en sachant qu'elle sera installée sur plusieurs systèmes différents. – Korchkidu