Хранение конфиденциальных данных приложения - PullRequest
3 голосов
/ 02 июля 2010

Я реализую приложение на Python, которое будет подключаться к нашим различным серверам и компьютерам.Все они имеют разные логины и пароли.Я хочу хранить всю эту информацию непосредственно в приложении и запрашивать только один главный логин / пароль.Как я могу сохранить все эти конфиденциальные данные в приложении, чтобы тот, кто не имеет мастер-пароля, не смог получить доступ к нашим серверам и компьютерам?

РЕДАКТИРОВАТЬ: возможно ли сохранить зашифрованный файл длясохранить эти данные?

EDIT2: Мое приложение в настоящее время работает под окнами.Я перенесу его на linux и MAC OSX, если это возможно.

EDIT3: для тех, кто заинтересован, я использовал M2secret + M2Crypto для шифрования текстового файла.При запуске приложения пользователь должен ввести пароль, который используется для расшифровки файла и загрузки необходимых учетных данных в приложение.Кажется, работает так ...

С уважением.

1 Ответ

1 голос
/ 02 июля 2010

Это звучит как очень плохая идея. Вы можете зашифровать логины и пароли, но любой, кто имеет доступ к мастер-паролю, получит доступ ко всем отдельным логинам. Это означает, что вы можете гарантировать, что отдельные учетные записи долго не будут оставаться секретными, и если они все-таки просочатся, вам придется изменить их все.

Лучшим решением было бы дать каждому пользователю вашего приложения свой логин на каждом из ваших серверов. Тогда ваше приложение может использовать один и тот же логин / пароль для каждого сервера, к которому оно обращается, и пароль вообще не нужно хранить в приложении. Если пароль одного пользователя утек, вы просто меняете его пароль на всех своих логинах, и другие пользователи не затрагиваются.

В качестве альтернативы можно направить все входы в систему через один прокси-сервер: прокси-сервер может находиться в защищенной системе, поэтому никто из пользователей не может получить доступ к какой-либо из базовых учетных записей, и вы можете защитить доступ к прокси-серверу отдельными учетными записями пользователей. *

Я порылся в своем старом коде и нашел следующее из модуля, который я назвал '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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...