2010-07-02 7 views
2

J'implémente une application python qui se connecte à nos différents serveurs et ordinateurs. Ils ont tous des logins et des mots de passe différents. Je veux stocker toutes ces informations directement dans l'application et demander un seul identifiant/mot de passe principal. Comment puis-je stocker toutes ces données sensibles dans l'application afin que quelqu'un qui n'a pas le mot de passe principal ne puisse pas accéder à nos serveurs et ordinateurs?Stockage des données sensibles à l'application

EDIT: serait-il possible de stocker un fichier crypté pour stocker ces données?

EDIT2: Mon application fonctionne sous Windows pour le moment. Je vais le porter sur Linux et MAC OSX si possible.

EDIT3: pour ceux qui étaient intéressés, j'ai utilisé M2secret + M2Crypto pour crypter un fichier texte. Lors du lancement de l'application, l'utilisateur doit entrer un mot de passe qui est utilisé pour déchiffrer le fichier et charger les informations d'identification nécessaires dans l'application. Cela semble fonctionner comme ça ...

Cordialement.

Répondre

0

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) 
+0

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

+0

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

+0

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

Questions connexes