2010-07-02 163 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

相關問題