2010-07-02 187 views
2

我正在实现一个将连接到我们不同的服务器和计算机的python应用程序。他们都有不同的登录名和密码。我想直接将所有这些信息存储在应用程序中,只需要一个主登录名/密码。如何将所有这些敏感数据存储在应用程序中,以便没有主密码的人将无法访问我们的服务器和计算机?存储应用程序敏感数据

编辑:是否有可能存储加密文件来存储这些数据?

编辑2:我的应用程序在Windows下运行的时刻。如果可能,我会将它移植到linux和MAC OSX上。

EDIT3:对于那些有兴趣的人,我使用M2secret + M2Crypto来加密文本文件。启动应用程序时,用户必须输入用于解密文件并将所需凭据加载到应用程序中的密码。似乎这样工作...

此致敬礼。

回答

0

这听起来像一个非常糟糕的主意。您可以加密登录名和密码,但任何有权访问主密码的人都可以访问所有单个登录名。这意味着你可以保证个人登录不会长久保密,如果他们泄露了,你将不得不改变他们。

更好的解决方案是将每个用户的应用程序自己的登录名分配给每台服务器。然后,您的应用程序可以为其访问的每台服务器使用相同的登录名/密码,并且根本不需要将密码存储在应用程序中。如果一个用户的密码被泄露,您只需更改其所有登录名的密码,而其他用户不会受到影响。

或者将所有登录路由通过单个服务器代理:代理可以位于安全系统上,因此,每个用户都不会接近任何基础帐户,并且可以保护个人用户帐户对代理的访问。

我挖掘了一些旧的代码,并从我称之为'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) 
+0

感谢您的回答。但是,在这两种解决方案中,如果您丢失登录名/密码,则必须在所有服务器上更改它们。 其次,出于安全原因,我不想在所有服务器上使用相同的密码。 我必须添加一些细节: 1)我应该是唯一使用该应用程序的人。 2)目前,所有密码都存储在应用程序中。我现在要删除它们,以便如果有人使用我的电脑,他将不会访问服务器/计算机。 3)每台服务器都有自己的登录/密码配置。 感谢您的帮助! 此致敬礼。 – Korchkidu 2010-07-02 08:57:46

+0

好吧,所以你是唯一的用户,但你想保护你的应用程序使用的密码。你能否澄清你正在使用的系统:Windows还是Linux。如果Windows那么有win32 api调用,它允许你存储只能由你访问的加密数据。您不需要主密码,因为数据在您登录时可以访问,但在其他人登录时不会访问。如果是Linux,那么你可以使用gnome-keyring。 – Duncan 2010-07-02 11:46:26

+0

嗨,我更新了这个问题。但是,是的,我只是想知道它将安装在几个不同的系统上,以保护应用程序。 – Korchkidu 2010-07-13 05:35:15