Šifrování dat v klidu (Data-at-Rest Encryption)

LockMyCal implementuje robustní bezpečnostní vrstvu pro ochranu citlivých uživatelských a klientských údajů. Veškeré OAuth tokeny, přístupová hesla k CalDAV účtům a další citlivá data jsou v databázi PostgreSQL ukládána v zašifrované podobě pomocí vlastní implementace algoritmu AES-256-GCM.

Note

I v případě, že by došlo k neoprávněnému úniku celého SQL dumpu databáze, útočník bez hlavního kryptografického klíče nezíská přístup k tokenům propojených kalendářů ani k dalším uloženým přihlašovacím údajům.


Jak šifrování funguje

graph LR
    A["OAuth Tokeny / Hesla k CalDAV"] --> B["LockMyCal Kryptografická Vrstva (AES-256-GCM)"]
    K["DATA_ENCRYPTION_KEY"] --> B
    B --> C["Šifrovaný text (Ciphertext + IV + Tag)"]
    C --> D["PostgreSQL Databáze"]

1. Vygenerování šifrovacího klíče DATA_ENCRYPTION_KEY

Vygenerujete jej libovolným z následujících příkazů:

Pomocí OpenSSL:

openssl rand -base64 48

Pomocí Elixiru v Dockeru:

docker run --rm elixir:alpine elixir -e ":crypto.strong_rand_bytes(48) |> Base.encode64() |> IO.puts()"

2. Nastavení proměnné prostředí

Vygenerovaný řetězec vložte do vašeho .env souboru:

DATA_ENCRYPTION_KEY=VaseVygenerovaneBase64HesloOdelce48Bytu==

Pokud DATA_ENCRYPTION_KEY v .env nenastavíte, appka odvodí šifrovací klíč ze SECRET_KEY_BASE — funguje to, ale spojuje tím ochranu dat v klidu s klíčem pro podepisování sessions. Nastavení samostatného DATA_ENCRYPTION_KEY doporučujeme, aby šlo případně rotovat SECRET_KEY_BASE bez dopadu na uložená data.

Caution

Klíč DATA_ENCRYPTION_KEY po nastavení neměňte. Data zašifrovaná původním klíčem by pak nešla dešifrovat a propojené kalendáře a video služby by bylo nutné připojit znovu. Klíč bezpečně zálohujte spolu s .env.

3. Přechod z klíče odvozeného ze SECRET_KEY_BASE

Pokud jste instanci dosud provozovali bez DATA_ENCRYPTION_KEY, jsou uložené údaje zašifrované klíčem odvozeným ze SECRET_KEY_BASE. Po nastavení DATA_ENCRYPTION_KEY je jednorázově přešifrujte:

docker compose exec app bin/tymeslot eval 'Ecto.Migrator.with_repo(Tymeslot.Repo, fn _ -> IO.inspect(Tymeslot.Security.CredentialReencryption.run(), label: "reencryption") end)'

Příkaz je bezpečné spouštět opakovaně – opakujte ho, dokud nehlásí migrated_values: 0. Poté jsou oba klíče nezávislé a SECRET_KEY_BASE lze rotovat bez dopadu na uložená data.