Szyfrowanie połączeń między zarejestrowanymi użytkownikami i ich poufnymi danymi

Nov 20 2020

Chcę, aby łączenie użytkowników z ich poufnymi danymi bez ich haseł było niepraktyczne - nawet przy pełnym dostępie do bazy danych.

Ponadto, jeśli użytkownik ma wiele wrażliwych danych, chcę również uniknąć łączenia różnych elementów razem

Na podstawie komentarzy i poszukiwań zaktualizowałem pytanie.

I znaleźć a kilka podobnych pytań, ale nikt wydaje się podać szczegóły szukam, albo mają nieco inne wymagania wstępne (Udostępnianie danych f.ex.).

Tak więc, oprócz rejestrowania użytkowników strony internetowej i zarządzania nimi za pomocą standardowych operacji CRUD, przechowuję w bazie danych kilka potencjalnie wrażliwych danych od użytkowników. Pod tym względem to pytanie jest podobne, a dla mnie odpowiedzi są wskazówkami. W szczególności nie powinienem „przechowywać w [mojej] bazie danych niczego, co mogłoby zostać użyte do uzyskania klucza szyfrowania bez znajomości hasła”.

Strona klienta składa się z prostych stron html / css / js, a w tej chwili aplikacja komputerowa nie jest dostępna. Analizuję dane tylko w grupach (na podstawie zmiennych w danych), aby poszczególne dane nie były interesujące. Chcę jednak, aby użytkownicy mogli zobaczyć własne dane i, na przykład, usunąć dane, jeśli będą chcieli.

Myślę o wygenerowaniu klucza dla każdego fragmentu danych, zaszyfrowaniu pary klucz-data_id w bazie danych i odszyfrowaniu ich za każdym razem, gdy potrzebny jest niezaszyfrowany klucz, albo do przechowywania danych, albo gdy użytkownik chce zobaczyć swoje dane:

import json
from cryptography.fernet import Fernet


def get_key(password, data_id):

    # Check that the given password is valid
    if not self.check_password(password):
        raise KeyError('The given password is not valid')
    
    # Always use string representation of the data_id since json allows only string keys
    data_id_str = str(data_id)

    # Create a Fernet object with the password
    f = Fernet(password)
    
    # Set the encoding for the bytes <-> string conversion    
    encoding = 'utf-8'
    
    # Decrypt and load into a dict the existing keys
    if self.encrypted_keys:
    
        # Ensure that the encrypted keys are in bytes for the Fernet
        bytes_encrypted_keys = bytes(self.encrypted_keys)

        # Decrypt the encrypted keys and transform the bytes object into a string
        keys_string = f.decrypt(bytes_encrypted_key).decode(encoding)
        
        # Load the string into a dict
        keys_dict = json.loads(keys_string)
    
    # Create an empty dict if no keys defined
    else:
        keys_dict = {}
    
    # Try to get a key for the data_id
    try:
        key = keys_dict[data_id_str]
    
    # The key not found
    except KeyError:
        
        # Generate a new a URL-safe 32-byte key and decode as a string into the keys_dict 
        key = keys_dict.setdefault(
            data_id_str,
            Fernet.generate_key().decode(encoding),
        )
        
        # Turn the updated keys_dict into a string
        updated_keys_string = json.dumps(keys_dict)

        # Encode the string into bytes for the Fernet
        bytes_keys = updated_keys_string.encode(encoding)

        # Encrypt the updated keys
        self.encrypted_keys = f.encrypt(bytes_keys)

        # Save the encrypted keys into the database
        self.encrypted_keys.save()
    
    # Return the decrypted key for the data_id
    return key

Czy to wydaje się rozsądnym procesem? Czy brakuje mi jakichś oczywistych wad? Czy to przesada? Czy są inne rzeczy, które powinienem rozważyć?

Zdaję sobie sprawę, że słabym punktem w tym jest siła hasła. Spróbuję sobie z tym poradzić za pomocą standardowych testów wytrzymałości.

Rozumiem też, że dostęp do serwera daje możliwość przechwycenia procesu i przejęcia kluczy. Oczywiście, gdyby istniał sposób, aby temu zapobiec, bez aplikacji komputerowej, byłbym zainteresowany. Obecnie mam przynajmniej nadzieję, że uda mi się zabezpieczyć bazę danych.

Dziękuję za radę!

Odpowiedzi

user10216038 Nov 22 2020 at 03:44

Jeśli dobrze rozumiem:

Zapomnij o szyfrowaniu i deszyfrowaniu oraz ochronie klucza. Nic z tego nie jest konieczne.

Użyj skrótu w taki sam sposób, w jaki przechowywane są hasła.

Hash staje się unikalnym identyfikatorem danych bez ujawniania użytkownika.

Na podstawie hasła podanego przez użytkownika uzyskujesz odpowiednio złożony skrót. Użytkownik może później podać to hasło w celu ponownego zhaszowania w celu uzyskania pasującego identyfikatora dla jego danych.

Bez zamieszania, bez musów, bez zapisanych haseł.

--EDYTUJ dla nowo dodanego ograniczenia -

Ponadto, jeśli użytkownik ma wiele wrażliwych danych, chcę również uniknąć łączenia różnych elementów razem

Użyj losowego Salt, aby utworzyć inny identyfikator skrótu dla każdego obiektu BLOB danych. Bez innych ograniczeń musiałbyś obliczyć wartość skrótu dla każdej soli w systemie, aby znaleźć dopasowanie. Może to być trywialne dla setek, ale dla znacznie większych wartości możesz potrzebować dodatkowego ograniczenia.