Ik was bezig met het uitzoeken van assymetrische encryptie in PHP en hoopte dat iemand feedback zou kunnen geven of misschien wat tips had.
Situatie: Gebruikers van de applicatie moeten elkaar berichten/bestanden kunnen sturen, die niet door anderen geopend kunnen worden. Dus ook niet door de programmeur/sysadmin/hacker die root toegang heeft etc. Maar moet transparant zijn voor de gebruiker, dus niet zelf keys laten beheren ed.
Voorgestelde oplossing: Assymetrische encryptie op basis van public/private keys, zodat alleen de gebruiker voor wie het bedoeld is, het bestand kan lezen. Private key wordt in de database (of evt. filesystem) opgeslagen, met een passphrase/encryptie op basis van het wachtwoord van de gebruiker. Zonder het wachtwoord is het bestand dus niet decrypten, ook niet voor de systeembeheerder.
Vraag: Hoe blijft het systeem gebruiksvriendelijk, terwijl het nog wel veilig is? Het liefst vul je maar 1 keer je wachtwoord in, niet elke keer als je een bestand wil lezen. En als je je wachtwoord vergeet, ben je al je data kwijt..
Overwegingen:
Data opslaan in een sessie kan, maar in principe is dat ook file-based (of een andere database driver), maar in het geval van een hack zou de hacker die bestanden dus ook kunnen benaderen.
Dus idealiter zou je passphrase (of private key) bij de gebruiker bewaren.
Opslaan in cookies?
Ik ga uit van een applicatie op basis van Laravel, waarbij Cookies encrypted zijn, secure en http only.
Aangezien de cookies encrypted zijn, zouden we zodra de gebruiker inlogt, de passphrase kunnen decrypten met het gebruikerswachtwoord en opslaan in een cookie. (Wat waarschijnlijk efficiënter is als de hele key in de cookie bewaren, aangezien het met elke request meegestuurd wordt)
Is dit wel veilig? (Natuurlijk niet als de gebruiker zowel toegang heeft tot de user-cookies als root-toegang tot het systeem, maar dat lijkt me geen reëel scenario)
Key recovery?
Aangezien het wachtwoord de sleutel is, kan je niet meer bij je bestanden als je je wachtwoord vergeet. Een oplossing zou zijn om de passphrase ook te encrypten met een random string. Die random string mailen/geven we dan aan de gebruiker bij het registreren om zelf veilig te bewaren. In het geval van verlies van data kan die key gebruikt worden om alsnog bij je data te kunnen. (Al zal hier misschien een soort combinatie van e-mail validatie bij moeten zitten, anders komt het neer op het opschrijven van je wachtwoord)
Dus dan zou het er in de database zoiets uitzien:
table users
- id, email, name, password_hash etc
- public_key (plaintext)
- private_key (plaintext, beveiligd met passphrase)
- passphrase_encrypted (encrypted met user password)
- passphrase_recovery (zelf passphrase, maar encrypted met random string)
passphrase zelf is dan gewoon een random string van xx tekens die gegeneerd wordt bij aanmaken van de account.
Bij registreren:
- Random passphrase maken
- Passphrase encrypten met gekozen wachtwoord
- Passprhase encrypten met random recovery string, mailen naar gebruiken
Bij aanmaken bestand/bericht
- Ophalen public_key van doelgebruiker(s)
- Bericht encrypten met public key
Bij inloggen
- Ophalen passphrase, decrypten met wachtwoord
- Decrypted passphrase bewaren in (beveiligd) cookie
Bij lezen bericht
- Passphrase uit cookie halen
- Bericht decrypten met private key en passphrase.
Bij wijzigen wachtwoord
- passphrase decrypten met oude wachtwoord
- passphrase encrypten met nieuwe wachtwoord.
- Keys en passphrase blijven zelfde, dus bestanden intact.
Bij vergeten wachtwoord
- Extra optie voor invullen recovery code. Indien aanwezig, code gebruiken om passphrase te decrypten. Opnieuw encrypten met nieuwe wachtwoord. Bestanden zijn intact.
- Anders nieuwe public/private key pair maken. Bestanden zijn verloren.
Implementatie zou dan zijn op basis van openssl_seal of de Zend OpenSSL Filter, die als wrapper dient voor OpenSSL seal/open.
Situatie: Gebruikers van de applicatie moeten elkaar berichten/bestanden kunnen sturen, die niet door anderen geopend kunnen worden. Dus ook niet door de programmeur/sysadmin/hacker die root toegang heeft etc. Maar moet transparant zijn voor de gebruiker, dus niet zelf keys laten beheren ed.
Voorgestelde oplossing: Assymetrische encryptie op basis van public/private keys, zodat alleen de gebruiker voor wie het bedoeld is, het bestand kan lezen. Private key wordt in de database (of evt. filesystem) opgeslagen, met een passphrase/encryptie op basis van het wachtwoord van de gebruiker. Zonder het wachtwoord is het bestand dus niet decrypten, ook niet voor de systeembeheerder.
Vraag: Hoe blijft het systeem gebruiksvriendelijk, terwijl het nog wel veilig is? Het liefst vul je maar 1 keer je wachtwoord in, niet elke keer als je een bestand wil lezen. En als je je wachtwoord vergeet, ben je al je data kwijt..
Overwegingen:
Data opslaan in een sessie kan, maar in principe is dat ook file-based (of een andere database driver), maar in het geval van een hack zou de hacker die bestanden dus ook kunnen benaderen.
Dus idealiter zou je passphrase (of private key) bij de gebruiker bewaren.
Opslaan in cookies?
Ik ga uit van een applicatie op basis van Laravel, waarbij Cookies encrypted zijn, secure en http only.
Aangezien de cookies encrypted zijn, zouden we zodra de gebruiker inlogt, de passphrase kunnen decrypten met het gebruikerswachtwoord en opslaan in een cookie. (Wat waarschijnlijk efficiënter is als de hele key in de cookie bewaren, aangezien het met elke request meegestuurd wordt)
Is dit wel veilig? (Natuurlijk niet als de gebruiker zowel toegang heeft tot de user-cookies als root-toegang tot het systeem, maar dat lijkt me geen reëel scenario)
Key recovery?
Aangezien het wachtwoord de sleutel is, kan je niet meer bij je bestanden als je je wachtwoord vergeet. Een oplossing zou zijn om de passphrase ook te encrypten met een random string. Die random string mailen/geven we dan aan de gebruiker bij het registreren om zelf veilig te bewaren. In het geval van verlies van data kan die key gebruikt worden om alsnog bij je data te kunnen. (Al zal hier misschien een soort combinatie van e-mail validatie bij moeten zitten, anders komt het neer op het opschrijven van je wachtwoord)
Dus dan zou het er in de database zoiets uitzien:
table users
- id, email, name, password_hash etc
- public_key (plaintext)
- private_key (plaintext, beveiligd met passphrase)
- passphrase_encrypted (encrypted met user password)
- passphrase_recovery (zelf passphrase, maar encrypted met random string)
passphrase zelf is dan gewoon een random string van xx tekens die gegeneerd wordt bij aanmaken van de account.
Bij registreren:
- Random passphrase maken
- Passphrase encrypten met gekozen wachtwoord
- Passprhase encrypten met random recovery string, mailen naar gebruiken
Bij aanmaken bestand/bericht
- Ophalen public_key van doelgebruiker(s)
- Bericht encrypten met public key
Bij inloggen
- Ophalen passphrase, decrypten met wachtwoord
- Decrypted passphrase bewaren in (beveiligd) cookie
Bij lezen bericht
- Passphrase uit cookie halen
- Bericht decrypten met private key en passphrase.
Bij wijzigen wachtwoord
- passphrase decrypten met oude wachtwoord
- passphrase encrypten met nieuwe wachtwoord.
- Keys en passphrase blijven zelfde, dus bestanden intact.
Bij vergeten wachtwoord
- Extra optie voor invullen recovery code. Indien aanwezig, code gebruiken om passphrase te decrypten. Opnieuw encrypten met nieuwe wachtwoord. Bestanden zijn intact.
- Anders nieuwe public/private key pair maken. Bestanden zijn verloren.
Implementatie zou dan zijn op basis van openssl_seal of de Zend OpenSSL Filter, die als wrapper dient voor OpenSSL seal/open.