Enc: en krypterad meddelandetjänst baserat på engångslänkar

Permalänk
Medlem
Skrivet av Teknocide:

Varför så otrevlig ton? Jag lindade kanske inte in mitt budskap men avsikten var inte att säga åt dig att "RTFM".

Du får ursäkta mig. Jag blev bara rätt frustrerad/irriterad när du skrev att lösenordet skickas till servern. Det visade sig senare att det gör den, men då i hashad form (dock i klartext när du skrev ditt förra inlägg, vilket nu är fixat). Lösenordet i klartext skickas inte till servern, endast hashsträngen, vilket duger för tillfället. "Lösningen" är bättre än att skickas lösenordet i klartext, fram tills jag har lyckats lösa till det hela med fetch() (hoppas jag, har noll aning om hur slutresultatet kommer att bli med det).

Det var ett misstag från min sida att jag råkade ta bort $('[name="field-password"]').val(hashed_passwd); från share.js. Vet inte när det hände.

Men innan problemet upptäcktes av @Xcorp i gårnatt, blev jag bara frustrerad/irriterad över att både du och Xcorp hävdade att lösenordet skickades till servern ändå, även om "allt redan var fixat". Det var jag som var boven i dramat, jag läste inte på ordentligt, så felet i det här ligger hos mig och endast mig. Förlåt Men jag var såpass intygad över att jag hade fixat till det där och endast använt JavaScript till formuläret, så jag trodde problemet var löst och fick därmed en krock i huvudet.

Andra: "Skicka aldrig data i klartext till servern, för då kan servern läsa datan. Använd JavaScript istället."
Jag: byter till JavaScript.
Andra: "Datan skickas fortfarande i klartext till servern."
Jag: fixar till så att allt skickas krypterat och hashat.
Andra: "Datan skickas fortfarande i klartext till servern."
Jag: "Men allt skickas ju krypterat och hashat via JavaScript, precis som vad ni skrev att det skulle göras!"
Jag: försöker peta in och lära mig fetch() och är blind.
Andra: "Lösenordet skickas i klartext till servern."
Jag: "Men jag har ju för bövelen åtgärdat det!!"
Andra: "Lösenordet skickas i klartext till servern. Se och lär" *skickar skärmdump som bevis*
Jag: blir iskall och åtgärdar problemet fort som fan.

Jag är inte hemma i JavaScript och föredrar PHP, så man kan kalla mig för en nybörjare inom området. Avskyr Node.js. Är seg på att läras. Måste ha exempelkod eller främst färdig kod (vid lärande) och mycket tid innan något ens går in i huvudet på mig.

Livet med autism och uppmärksamhetsstörning...

Skrivet av Teknocide:

Det är just det jag menar, du ska ju inte lagra lösenordet någonstans, eftersom det bara ska finnas hos den som skrev meddelandet och den som ska läsa det.

Nu blev jag nyfiken. Hur ska webbsidan veta om lösenordet mottagaren anger är rätt eller fel, om lösenordet inte får vara i databasen (se @Pamudas lösning några inlägg upp) och inte heller i länken?

Skrivet av Teknocide:

Bcrypt är ett säkrare (tekniskt sett mer kostsamt) sätt för att hasha lösenord, det stämmer, men det är det ohashade lösenordet som används för kryptera och avkryptera datan, så varför hasha lösenordet alls?

För att man aldrig någonsin - oavsett vad - lagra ett lösenord i klartext. Se följande länk för anledningen till varför man ska hasha ett lösenord: https://security.stackexchange.com/a/36838. Dock blev jag nyfiken nu igen. Hur tycker du att ett lösenord ska på ett säkert sätt delas mellan 2 personer för en tjänst som Enc?

Skrivet av Teknocide:

Som sagt, om det hashade lösenordet aldrig används så är det väl meningslöst att hasha det till att börja med. Missar jag något här?

Hashsträngen används i page-read.js (i skrivande stund på rad 57) för att kolla om lösenordet är rätt eller fel.

Skrivet av Teknocide:

Min poäng här var att backendens jobb består i två saker:
1. Att lagra krypterad data och
2. Ge ut en referensnyckel till den krypterade datan, så att en läsare kan nå den genom en "snygg" URL.

Vad som är "snyggt" är ju subjektivt så klart, men jag menade någon sorts hash som unikt identifierar den lagrade datan.

Då förstår jag. Så, vad jag förstod det som på dig här nu, så ska länken innehålla det hashade lösenordet?

Visa signatur

Citera mig om du vill att jag ska hitta till ditt svar.
airikr.me. Andra projekt: Keizai, Koroth, Serenum & Enc.

Permalänk
Medlem
Skrivet av Airikr:

Du får ursäkta mig. Jag blev bara rätt frustrerad/irriterad när du skrev att lösenordet skickas till servern. […]

Ingen fara, jag kunde ha använt en trevligare ton.

Citat:

Hashsträngen används i page-read.js (i skrivande stund på rad 57) för att kolla om lösenordet är rätt eller fel.

[…] Så, vad jag förstod det som på dig här nu, så ska länken innehålla det hashade lösenordet?

Jag tänkte mig snarare en hash på den krypterade datan—men jag ser att du använder ett UUID vilket fungerar lika bra! Lösenordet, hashat eller ej, ska aldrig behöva skickas separat till servern. Om jag har läst den senaste versionen av din kod rätt så skapar du länken för läsning på klientsidan och skickar faktiskt aldrig lösenordet till servern, så själva "skickandes av lösenord" är ju löst.

Det kvarstår ett par problem:

1. Den krypterade datan är inte signerad, så det går inte att verifiera att innehållet inte har ändrats. Detta innebär att servern kan modifiera innehållet i filen utan att användaren märker detta.
2. Det går inte att verifiera att läsaren har angett rätt lösenord.

Att lägga till det BCryptade lösenordet i länken löser tekniskt sett 2. men löser inte 1.

Vad du önskar göra när en läsande användare anger ett lösenord är att använda det för att först verifiera att den krypterade datan är oförändrad (dvs att servern inte har gjort något fuffens med den), samt att avkryptera den.

Bägge problem kan lösas med en kombination av AES (förslagsvis) och MAC. Idén är att skapa en signatur av den krypterade datan som bara går att verifiera om både signaturen och den krypterade datan ej har ändrats av något eller någon. Signaturen behöver delges till läsaren på något sätt, men det går att bädda in den i den krypterade datan.

För att undvika att uppfinna hjulet på nytt och/eller skapa helt nya säkerhetsbrister kan du använda dig av en färdig variant som gör precis det här och kallas GCM; teknikerna och processen beskrivs bättre här: https://security.stackexchange.com/a/63134.

Förhoppningsvis går det att hitta ett trevligt bibliotek som löser GCM åt dig, annars får du hålla tungan rätt i mun och följa en guide i den här stilen: https://medium.com/@thomas_40553/how-to-secure-encrypt-and-de...

Notera att jag är en intresserad lekman och ingen expert. Jag kan inte avgöra om lösningarna som jag länkat till ovan faktiskt implementerar den bästa lösningen på problemet, men det är intressant läsning om inte annat!

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Airikr:

...
Men innan problemet upptäcktes av @Xcorp i gårnatt, blev jag bara frustrerad/irriterad över att både du och Xcorp hävdade att lösenordet skickades till servern ändå, även om "allt redan var fixat". Det var jag som var boven i dramat, jag läste inte på ordentligt, så felet i det här ligger hos mig och endast mig. Förlåt Men jag var såpass intygad över att jag hade fixat till det där och endast använt JavaScript till formuläret, så jag trodde problemet var löst och fick därmed en krock i huvudet.

Andra: "Skicka aldrig data i klartext till servern, för då kan servern läsa datan. Använd JavaScript istället."
Jag: byter till JavaScript.
Andra: "Datan skickas fortfarande i klartext till servern."
Jag: fixar till så att allt skickas krypterat och hashat.
Andra: "Datan skickas fortfarande i klartext till servern."
Jag: "Men allt skickas ju krypterat och hashat via JavaScript, precis som vad ni skrev att det skulle göras!"
Jag: försöker peta in och lära mig fetch() och är blind.
Andra: "Lösenordet skickas i klartext till servern."
Jag: "Men jag har ju för bövelen åtgärdat det!!"
Andra: "Lösenordet skickas i klartext till servern. Se och lär" *skickar skärmdump som bevis*
Jag: blir iskall och åtgärdar problemet fort som fan.

Jag är inte hemma i JavaScript och föredrar PHP, så man kan kalla mig för en nybörjare inom området. Avskyr Node.js. Är seg på att läras. Måste ha exempelkod eller främst färdig kod (vid lärande) och mycket tid innan något ens går in i huvudet på mig.

Livet med autism och uppmärksamhetsstörning...

Nu blev jag nyfiken. Hur ska webbsidan veta om lösenordet mottagaren anger är rätt eller fel, om lösenordet inte får vara i databasen (se @Pamudas lösning några inlägg upp) och inte heller i länken?

Jag tror missförståndet ligger här i, när vi har skrivit Javascript så har vi menat client-side, inget NodeJS eller liknande.

I frågan om hur websidan ska veta att det är rätt lösenord så gav jag dig alternativet WebCryptoAPI som vad jag förstått det har funktionen inbyggd.
Ett annat alternativ som jag kom på efter jag skrev mitt svar är att du på text-strängen bara lägger till "ENC!" eller liknande INNAN du krypterar den. När det sen avkrypteras så kollar du bara om de första fyra tecknen är "ENC!" Att någon matar in ett lösenord som vid avkryptering ger samma första tecken men inte resten är i praktiken omöjligt.
Du kan också bygga vidare på förslaget från @Teknocide om att hasha in-datan och kontrollera om det blir samma hash efter mottagaren har angett ett lösenord. Du behöver faktiskt inte ens spara hashen på servern, bara lägg den som en GET-parameter.
Båda lösningarna undviker helt att lösenordet sparas på servern i någon form.

Permalänk
Medlem

Ni får ursäkta mitt sena svar, men jag har verkligen inte haft någon programmeringsglöd de senaste dagarna.

Skrivet av Teknocide:

Ingen fara, jag kunde ha använt en trevligare ton.

Jag tänkte mig snarare en hash på den krypterade datan—men jag ser att du använder ett UUID vilket fungerar lika bra! Lösenordet, hashat eller ej, ska aldrig behöva skickas separat till servern. Om jag har läst den senaste versionen av din kod rätt så skapar du länken för läsning på klientsidan och skickar faktiskt aldrig lösenordet till servern, så själva "skickandes av lösenord" är ju löst.

Det kvarstår ett par problem:

1. Den krypterade datan är inte signerad, så det går inte att verifiera att innehållet inte har ändrats. Detta innebär att servern kan modifiera innehållet i filen utan att användaren märker detta.
2. Det går inte att verifiera att läsaren har angett rätt lösenord.

Att lägga till det BCryptade lösenordet i länken löser tekniskt sett 2. men löser inte 1.

Vad du önskar göra när en läsande användare anger ett lösenord är att använda det för att först verifiera att den krypterade datan är oförändrad (dvs att servern inte har gjort något fuffens med den), samt att avkryptera den.

Bägge problem kan lösas med en kombination av AES (förslagsvis) och MAC. Idén är att skapa en signatur av den krypterade datan som bara går att verifiera om både signaturen och den krypterade datan ej har ändrats av något eller någon. Signaturen behöver delges till läsaren på något sätt, men det går att bädda in den i den krypterade datan.

För att undvika att uppfinna hjulet på nytt och/eller skapa helt nya säkerhetsbrister kan du använda dig av en färdig variant som gör precis det här och kallas GCM; teknikerna och processen beskrivs bättre här: https://security.stackexchange.com/a/63134.

Förhoppningsvis går det att hitta ett trevligt bibliotek som löser GCM åt dig, annars får du hålla tungan rätt i mun och följa en guide i den här stilen: https://medium.com/@thomas_40553/how-to-secure-encrypt-and-de...

Notera att jag är en intresserad lekman och ingen expert. Jag kan inte avgöra om lösningarna som jag länkat till ovan faktiskt implementerar den bästa lösningen på problemet, men det är intressant läsning om inte annat!

Signering och verifiering av lösenord via HMAC är nu inlagd på Enc. Jag tog den kod som @Pamudas lade in i sitt inlägg här: #20673557

Det som är kvar nu, är bland annat att byta från SQLite till JSON så att jag kan hantera allt via JavaScript (ni vet, ändra is_unlocked från NULL till 1 när meddelandet är öppnat). Vill försöka hålla mig till endast JavaScript så mycket som jag bara kan, för det här projektet. Alla de ändringar jag har gjort i natt, är fullösningar. Fullösningar som funkar tills vidare

Jag ska kanske ta en titt på GCM. Allt beror på hur invecklat det är.

Skrivet av Xcorp:

Jag tror missförståndet ligger här i, när vi har skrivit Javascript så har vi menat client-side, inget NodeJS eller liknande.

Är inte Node.js också på klientnivå? Eller är det Node.js som man måste köra igång med hjälp av terminalen?

Skrivet av Xcorp:

I frågan om hur websidan ska veta att det är rätt lösenord så gav jag dig alternativet WebCryptoAPI som vad jag förstått det har funktionen inbyggd.
Ett annat alternativ som jag kom på efter jag skrev mitt svar är att du på text-strängen bara lägger till "ENC!" eller liknande INNAN du krypterar den. När det sen avkrypteras så kollar du bara om de första fyra tecknen är "ENC!" Att någon matar in ett lösenord som vid avkryptering ger samma första tecken men inte resten är i praktiken omöjligt.
Du kan också bygga vidare på förslaget från @Teknocide om att hasha in-datan och kontrollera om det blir samma hash efter mottagaren har angett ett lösenord. Du behöver faktiskt inte ens spara hashen på servern, bara lägg den som en GET-parameter.
Båda lösningarna undviker helt att lösenordet sparas på servern i någon form.

Ta gärna en titt på ändringsloggen. Har jag missat något, eller ser allt bra ut?

Visa signatur

Citera mig om du vill att jag ska hitta till ditt svar.
airikr.me. Andra projekt: Keizai, Koroth, Serenum & Enc.

Permalänk

Tjo!

@Airikr NodeJS, BunJS, och DenoJS är alla JavaScript för servrar (komiskt nog det motsatta till varför JavaScript togs fram, men det är en annan oändlig diskussion) även om de kan bygga på samma/liknande JS-motorer som körs i webbläsaren/"på klientsidan".

Testa gärna att öppna webbläsarens konsol på valfri webbsida och skriv sedan console.log(document.body). Gör sedan samma sak i NodeJS-terminalen i VSCode. Notera sedan vilken som säger att document-objektet saknas.

Vissa JavaScript-objekt och/eller -API:er finns endast "på klientsidan" och vissa endast "på serversidan".

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

Permalänk
Medlem

Nu har släppt ännu en säkerhetsuppdatering. Se ändringsloggen här: https://codeberg.org/airikr/enc/commit/0126866fb356c2fdc3d233...

Skrivet av WebbkodsFrilansaren:

Tjo!

@Airikr NodeJS, BunJS, och DenoJS är alla JavaScript för servrar (komiskt nog det motsatta till varför JavaScript togs fram, men det är en annan oändlig diskussion) även om de kan bygga på samma/liknande JS-motorer som körs i webbläsaren/"på klientsidan".

Testa gärna att öppna webbläsarens konsol på valfri webbsida och skriv sedan console.log(document.body). Gör sedan samma sak i NodeJS-terminalen i VSCode. Notera sedan vilken som säger att document-objektet saknas.

Vissa JavaScript-objekt och/eller -API:er finns endast "på klientsidan" och vissa endast "på serversidan".

Mvh,
WKF.

Tjena, @WebbkodsFrilansaren Tack för informationen.

Visa signatur

Citera mig om du vill att jag ska hitta till ditt svar.
airikr.me. Andra projekt: Keizai, Koroth, Serenum & Enc.