Non-encrypted confidential information - Local data - Python

Non-encrypted confidential information - Local data - Python

Need

Secure storage of confidential data on local devices

Context

  • Requirement of Python 3.7 or later for running the application
  • Usage of firebase_admin for server-side Firebase operations
  • Usage of Google Cloud Firestore for managing and storing data in a NoSQL database

Description

Non compliant code

        import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore

# Fetch the service account key JSON file contents
cred = credentials.Certificate('path/to/serviceAccountKey.json')

# Initialize the app with a service account, granting admin privileges
firebase_admin.initialize_app(cred)

db = firestore.client()

# Fetch some confidential data from Firestore
users_ref = db.collection('users')
docs = users_ref.get()

# Store the confidential data in a local file in plain text
with open('local_data.txt', 'w') as file:
    for doc in docs:
        file.write(f'{doc.id}: {doc.to_dict()}\\n')
        
        

The above Python code is an example of a Django backend application that interacts with Firebase to fetch some confidential data (in this case, user data) and stores it in a local file ( local_data.txt) in plain text.

The vulnerability lies in the fact that the confidential Firebase data is stored without any encryption. This means that if an attacker gets access to the physical device and manages to bypass the device's security mechanisms, they can easily view this confidential data.

The vulnerable part of the code is where we open a file and write the fetched data into it without any form of encryption:

                with open('local_data.txt', 'w') as file:
    for doc in docs:
        file.write(f'{doc.id}: {doc.to_dict()}\\n')

            


In this block, doc.id and doc.to_dict() represent the user's ID and their associated data, respectively. This information is written to the file as a string in plain text, which makes it very easy for anyone with access to the file to view the data.

Steps

  • Use a secure method to store confidential data, such as Keychain for iOS, Keystore for Android, or Windows Credentials for Windows.
  • Encrypt the data before storing it locally. You can use libraries like PyCryptodome in Python to encrypt and decrypt data.
  • Avoid storing sensitive data on the device whenever possible. If it's necessary, ensure it's securely deleted as soon as it's no longer needed.
  • Implement access controls to restrict who can access the stored data.
  • Regularly update and patch your systems to protect against known vulnerabilities.

Compliant code

        import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

# Fetch the service account key JSON file contents
cred = credentials.Certificate('path/to/serviceAccountKey.json')

# Initialize the app with a service account, granting admin privileges
firebase_admin.initialize_app(cred)

db = firestore.client()

# Fetch some confidential data from Firestore
users_ref = db.collection('users')
docs = users_ref.get()

# Generate a random 256-bit key for AES encryption
key = get_random_bytes(32)

# Create a new AES cipher object with the key
cipher = AES.new(key, AES.MODE_EAX)

# Store the confidential data in a local file after encryption
with open('local_data.txt', 'wb') as file:
    for doc in docs:
        # Convert the document to a string and encode it to bytes
        data = f'{doc.id}: {doc.to_dict()}\\n'.encode()
        # Encrypt the data
        ciphertext, tag = cipher.encrypt_and_digest(data)
        # Write the encrypted data to the file
        [file.write(x) for x in (cipher.nonce, tag, ciphertext)]
        
        

The updated code now encrypts the confidential data before storing it locally. This is done using the PyCryptodome library, which provides a collection of cryptographic recipes and primitives to Python developers.

A random 256-bit key is generated for AES encryption. This key is used to create a new AES cipher object. The confidential data is then converted to a string and encoded to bytes, which is then encrypted using the cipher object. The encrypted data is then written to the local file.

This way, even if an attacker gains access to the physical device and bypasses the device security mechanism, they would not be able to view the confidential data without the encryption key. This significantly reduces the risk of data exposure in case of device theft or loss.

References