Vraag:
Hoe kan ik veilig zijn met een globaal zout?
Toto
2013-10-07 19:33:10 UTC
view on stackexchange narkive permalink

Als ik de basis van het hashen en opslaan van wachtwoorden begrijp, hebben we het volgende nodig:

  1. een 'sterk' zout
  2. een "echt" willekeurig zout
  3. een uniek zout per wachtwoord
  4. een wachtwoordhashing functie met hoge CPU-kosten

We hashen de wachtwoorden met 1, 2, 3 en 4 met PHP crypt () en CRYPT_BLOWFISH met "gemiddelde" kosten.

We hebben een nieuwe behoefte: we moeten de hashes kunnen vergelijken, omdat we hebben gemerkt dat oplichting op laag niveau / spam / scamsters dezelfde wachtwoorden gebruiken. We hoeven het wachtwoord van een misbruiker niet te kennen, maar alleen om te weten dat een profiel hetzelfde wachtwoord gebruikt als een eerder geïdentificeerde misbruiker.

Dus we denken erover om 2 velden in onze database te hebben:

  • wachtwoordA: gebruikt voor inlogprocedure (dit veld zou 1, 2, 3 en 4 gebruiken)

crypt ($ wachtwoord, '$ 2y $ 06 $ '. $ uniqueSalt);

  • wachtwoordB: gebruikt om te "vergelijken" (dit veld zou ons 1, 2 en 4 zijn)

crypt (md5 (md5 ($ wachtwoord). $ globalSaltA). $ globalSaltB, '$ 2y $ 10 $'. $ globalSaltC);

Globale zouten A en B zouden worden opgeslagen alleen in de applicatiecode.

Om het ontbrekende punt 3 voor wachtwoordB te compenseren, hebben we de "kosten" verhoogd, wat een stuk hoger is.

Naar aanleiding van de opmerking begreep ik hoe onveilig deze strategie is als een aanvaller een volledige toegang (database + code) krijgt op de server. Als de aanvaller echter alleen de database krijgt, gaat het goed.

Bedrijven die creditcardfraude detecteren, hebben hetzelfde probleem met de creditcardnummers. Ze kunnen ze niet opslaan, maar ze moeten ze vergelijken.

Welke strategie / oplossing zou je adviseren?

Wereldwijd zout = peper
Kanttekening: ik denk dat u zult zien dat bedrijven die creditcardfraude opsporen ** de cijfers wel opslaan. PCI stelt hen in staat om dat te doen zolang ze onleesbaar worden gemaakt door codering of een equivalent. En ze hebben de originele nummers nodig om zaken als accountupdates af te handelen - als je een vervangende kaart krijgt, gaat er een melding uit dat oude kaart X gelijk is aan nieuwe kaart Y. In plaats van te spelen met games om hashes te verzwakken en te versterken, moet je misschien gewoon de "vergelijk" versies en wees heel voorzichtig, de sleutel kan niet tegelijk met de database gecompromitteerd worden.
Vier antwoorden:
Thomas Pornin
2013-10-10 04:06:20 UTC
view on stackexchange narkive permalink

Het kernprobleem: als uw server efficiënt een gehasht wachtwoord kan vergelijken met (mogelijk) alle de gehashte wachtwoorden voor de hele gebruiker, dan kan een aanvaller dat ook. Een aanvaller die een kopie van uw serverbestanden / database bemachtigt, kan een offline woordenboekaanval uitvoeren, dwz het potentiële wachtwoord hashen en zoeken naar een overeenkomst.

Bij normale wachtwoordhashing wordt een salt per wachtwoord gebruikt om voorkomen parallelle aanvallen: we willen dat de aanvaller de volledige rekenprijs van de hash-functie betaalt (die door vele iteraties duur wordt gemaakt) voor elk wachtwoord en elk gebruikersaccount. Als verschillende wachtwoord-hashes echter hetzelfde salt gebruiken, kan de aanvaller een potentieel wachtwoord proberen tegen allemaal voor de kosten van één aanroep van een hash-functie. Dus uw "globale zout" verzwakt het schema aanzienlijk: het stelt de aanvaller in staat om 1000 accounts aan te vallen voor de kosten van een aanval.

Het belangrijke punt: uw probleem is er een van tijdelijkheid. In feite wil je een nieuw gebruikerswachtwoord niet vergelijken met alle wachtwoorden van alle andere gebruikers; wat u wilt, is het wachtwoord dat door elke gebruiker is gekozen tijdens de registratie, vergelijken met een beperkte lijst van "wachtwoorden van bekende overtreders". Wanneer een geregistreerde gebruiker de status "overtreder" krijgt, is hij helaas al geregistreerd en is zijn wachtwoord niet bewaard gebleven, alleen de hash ervan. U wilt dus echt toegang hebben tot het wachtwoord dat is gebruikt voor de registratie nadat de registratie heeft plaatsgevonden.

Een mogelijke oplossing: gebruik escrowing, ook bekend als asymmetrische versleuteling. Maak een RSA-sleutelpaar. Bewaar de openbare sleutel op de server. Bewaar de bijbehorende privésleutel NIET op de server; bewaar het in plaats daarvan ergens anders, bijv. op een laptop die offline wordt bewaard (of misschien slechts op een paar USB-sticks).

Wanneer een gebruiker zich registreert, hasht hij zijn wachtwoord zoals gewoonlijk (met PBKDF2, veel iteraties, een nieuwe willekeurige salt, enz.). Maar codeer het wachtwoord (niet de hash) met de RSA-sleutel, en sla het coderingsresultaat op in uw database, samen met de hash. Versleuteling heeft alleen de openbare sleutel nodig en is willekeurig, dus deze versleutelde versie geeft geen extra invloed aan een aanvaller die een kopie van de database-inhoud krijgt. Wanneer een gebruiker inlogt, wordt de wachtwoordhash gebruikt, zoals gewoonlijk.

Wanneer een gebruiker een spammer blijkt te zijn, haalt u de privésleutel op en decodeert u het geblokkeerde wachtwoord. Op die manier verkrijgt u het "slechte wachtwoord" en kunt u dit toevoegen aan de lijst met wachtwoorden die u bij registratie wilt weigeren. Die lijst kan als duidelijke tekst worden bewaard: aangezien de bijbehorende rekeningen zijn gesloten, is daar geen probleem mee. Zorg ervoor dat u de decodering uitvoert op een "veilige" machine, bij voorkeur offline: u wilt echt niet dat die privésleutel wordt gestolen.


Een waarschuwing: spammers zijn als bacteriën, in dat ze de neiging hebben om te evolueren met betrekking tot externe beperkingen. Als je spammers eruit filtert op basis van hun gewoonte om wachtwoorden te hergebruiken voor registratie, zul je ze snel leren om willekeurige wachtwoorden te genereren. Daarom voorspel ik dat als je zo'n systeem installeert, het na relatief korte tijd niet meer effectief zal zijn om spammers eruit te schoppen; daarna is het gewoon dood gewicht in uw database (niet veel, want een RSA-gecodeerd kort bericht met een 2048-bits RSA-sleutel is slechts 256 bytes, maar niettemin dood gewicht).

Verdorie, je hoeft niet eens de privésleutel te bewaren.
Leuke oplossing. Ik wou dat ik twee ups kon geven :-)
AJ Henderson
2013-10-07 19:48:28 UTC
view on stackexchange narkive permalink

Dat kan niet. Het maakt de zekerheid van het hebben van een uniek zout (of welk zout dan ook) volledig ongedaan. Het punt van een uniek zout is dat het het gebruik van een regenboogtafel voorkomt om het wachtwoord te identificeren. Door op te slaan met een globale salt kan die tafel worden aangevallen met een regenboogtafel en hoogstwaarschijnlijk in veel gevallen het originele wachtwoord identificeren.

Het alternatief hiervoor is om een ​​lijst met salts te genereren om een ​​nieuw wachtwoord tegen te proberen. (degene die zijn gekoppeld aan eerdere spammers). Het maakt het aanmaken van een nieuwe gebruiker een iets moeilijkere bewerking, aangezien je de wachtwoordhash meerdere keren moet uitvoeren, maar het is de enige veilige manier om te doen waar je het over hebt. Het maken van nieuwe gebruikers zou ook de enige keer moeten zijn dat u deze stap moet uitvoeren, dus het zou niet een te grote hit moeten zijn. Ik zou het ook alleen aanraden als andere indicatoren lijken te ondersteunen dat het een spamgebruiker is, als je de impact verder wilt verminderen.

Je kunt ook slechte wachtwoorden opslaan nadat ze zijn geïdentificeerd om de lijst kort te houden . De vorige gebruiker met salt 1234 had bijvoorbeeld een hash abcd. Wanneer een nieuwe gebruiker het wachtwoord "ImSpam" indient en u het probeert tegen salt 1234, ziet u dat het abcd is en nu het daadwerkelijke wachtwoord voor dat salt kent, dus u kunt stoppen met het controleren en het wachtwoord alleen volledig weigeren. Dit zou de lijst relatief kort moeten houden. Je kunt ook oude spamgebruikers mogelijk laten verouderen, want als je al een tijdje niet bent aangevallen door die spammer, is de kans groot dat ze het opgaven.

Wat we begrepen, is dat salt het succes van een aanval niet verhindert, maar kosten die resulteren in CPU-behoeften wel. Daarom hebben we de kostenwaarde verhoogd naar '10' en meer zout en MD5 toegevoegd om gebruik van de regenboogtafel te voorkomen. Maar een aanvaring / verjaardagsaanval is mogelijk. Elk uur zien we misbruikers. Het probleem is dat de analyse wordt gedaan door een statistische risicobeoordelingstoepassing die we voeden met onbewerkte gegevens, dus we moeten een "weergave" van het wachtwoord op een of andere manier vergelijken. De tool herberekent het risiconiveau van elke gebruiker elke keer dat er nieuwe onbewerkte gegevens worden toegevoegd (zodat we gemiste misbruikers kunnen opsporen).
@Toto - je vermindert de complexiteit met ordes van grootte door niet te zouten. Als u het resultaat van een globaal zout gaat opslaan, kunt u net zo goed helemaal geen zout voor opslag gebruiken, want dat is het punt van mislukking en heeft de minste complexiteit om op te lossen. Het idee van een salt is dat het een aparte aanval op elk wachtwoord vereist. Een globaal zout / geen zout zorgt ervoor dat alle zwakke wachtwoorden in één klap kunnen worden gevonden. De unieke salts voorkomen dat de zwakke wachtwoorden gemakkelijk kunnen worden geïdentificeerd.
Ik heb ook beschreven wat je moet doen, voor een nieuwe gebruiker, het door hem verstrekte wachtwoord nemen en het hashen met elk van de bekende slechte gebruikerszouten en kijken of het overeenkomt. Zodra u een wachtwoord van een slechte gebruiker hebt geïdentificeerd (op basis van hun tweede poging om zich ermee te registreren), kunt u dat wachtwoord als slecht opslaan en de salt van de lijst verwijderen omdat het wachtwoord niet langer onbekend is.
Goed punt! Helaas kunnen we deze oplossing niet implementeren omdat de risicobeoordeling continu wordt gedaan en niet alleen bij het maken van het profiel. :(
@Toto - nou, als je er genoeg rekenkracht naar toe kunt gooien, kun je willekeurig gebruikerslogins doorzoeken met hun wachtwoord tegen de slechte hashes wanneer ze inloggen of wachtwoorden wijzigen, maar dat is veel minder efficiënt. U kunt ook doorlopende tests uitvoeren van de lijst met geïdentificeerde slechte wachtwoorden met bestaande unieke salts om problemen te identificeren zodra ze voor het eerst zijn gedetecteerd.
John Deters
2013-10-09 04:12:55 UTC
view on stackexchange narkive permalink

Laten we de uniek gezouten hashes "beter" noemen en de globale / enkelvoudig gezouten hashes "slechter". Om prestatieredenen wilt u misschien de betere hashes in de gebruikersdatabase behouden, zodat u gebruikers snel kunt verifiëren. Ik raad aan om de "slechtere" hashes naar een andere, meer beveiligde server te verplaatsen met een dunne, eenvoudige, geverifieerde interface die bestaat uit twee methoden: AddPassword (userId, wachtwoord) en Blacklist (spammerUserId).

AddPassword rapporteert eenvoudigweg succes of mislukking. Blacklist voegt de id van de spammer toe aan de zwarte lijst en retourneert een lijst met alle userIds die overeenkomen met het wachtwoord van de spammer. Maar pas op: iedereen die toegang heeft, kan een woordenboek gebruiken tegen uw Blacklist-methode, waardoor legitieme gebruikers worden vergiftigd en lijsten met overeenkomende wachtwoorden worden verzameld.

Intern zou je ze kunnen opslaan zoals je wilt: gehashte, gezouten, gecodeerde of duidelijke tekst. Je moet die machine gewoon veilig op slot houden.

Luc
2013-10-10 02:04:23 UTC
view on stackexchange narkive permalink

Zoals @AJHenderson al zei, is het simpele antwoord dat je dat niet kunt. Je begrijpt waarom een ​​uniek zout nodig is, en je mist hiervoor geen enkele wiskundige truc, het is echt onmogelijk in combinatie met een uniek zout. Dat gezegd hebbende, dit is hoe ik het probleem zou oplossen:

1. Ik zou een nieuw databaseveld toevoegen met de naam zoiets als UnsaltedPassword en het vullen met alle NULL-waarden. Elke keer dat iemand zijn / haar wachtwoord registreert of wijzigt, vul het dan in met een hash van het wachtwoord, alleen zonder salt en tien keer sterker dan de andere hashing-methode.

2. Wijzig de aanmeldingsprocedure zodat deze controleert of de gebruiker een NULL-waarde in dat veld heeft, en als de gebruiker dat doet, vult u het veld in. Als dit teveel belasting zou veroorzaken, voer de hashfunctie dan alleen uit voor bepaalde accounts, zoals mensen met een lage postcount of gewoon door een willekeurige kans (bijv. Voer de hash uit met een kans van 1 op 10).

3 . Ten slotte zou ik het controleren op dubbele wachtwoorden toevoegen wanneer het veld is gevuld, en ook controleren op een zwarte lijst. Mensen met duplicaten kunnen worden gemarkeerd (mogelijk ook verteld dat ze een zwak wachtwoord gebruiken), en de zwarte lijst wordt onmiddellijk verbannen (of helemaal verboden, indien mogelijk).

Wachtwoordwijzigingen komen niet zo vaak voor in vergelijking met logins (alle keren dat de andere hash-functie met salt moet worden uitgevoerd), dus ik denk dat het logisch is om twee verschillende hash-velden in de database te hebben voor verschillende doeleinden. Ook zou een tien keer sterker moeten kunnen worden gedaan, of misschien zou je zelfs meer kunnen doen (1 tot 2 seconden hashingtijd is waar ik naar streef, aangezien het vrijwel een eenmalige deal is). Het is waarschijnlijk duurder voor aanvallers om deze te kraken dan om alleen het unieke zout toe te passen.

Ik denk dat ik iets mis omdat ongezouten hashing (zelfs met een hoog aantal rondes / kosten) onveilig is (regenboogwoordenboeken), nietwaar?
@Toto: Ik denk dat Luc databasetabel bedoelde in plaats van veld. Een nieuwe tabel, zonder enige link naar de hoofdgebruikersdatabasetabel, zou het volstaan, maar het opslaan van deze informatie samen met de gebruikersnaam is echt slecht. Dat komt omdat ongezouten wachtwoorden gemakkelijk kunnen worden aangevallen met regenboogtafels. Het zou triviaal zijn om een ​​regenboogtabel met gemeenschappelijke wachtwoorden te genereren en naar overeenkomsten te zoeken. Als u vervolgens een match krijgt, kan de login worden uitgevoerd als de aanvaller ook weet wat de inlognaam voor dat wachtwoord is.
Vorige opmerking was te groot. Laatste opmerking: in ieder geval denk ik niet dat de techniek die Luc blootlegde de vraag zou beantwoorden, aangezien de eigenaar van de website zowel de gebruikersnaam * als * het wachtwoord zou moeten weten, en er is geen veilige manier om te doen wat was gesteld in de vraag, omdat exact hetzelfde dat de website-eigenaar zou moeten doen, door de aanvaller kan worden gedaan. Het dichtst bij een oplossing is wat in een ander antwoord werd genoemd, in die zin dat het wachtwoord ook in de * versleutelde * versie wordt opgeslagen en de privésleutel offline wordt bewaard.
@jpkrohling "ongezouten wachtwoorden kunnen gemakkelijk worden aangevallen met regenboogtabellen". Zou je een regenboogtabel willen genereren waarbij elke hash 0.1s kost (waarna je het nog steeds tegen de gebruikersdatabase moet draaien), of de gezouten wachtwoorden (zonder regenboogtabel) kraken die slechts 0.001s per hash per gebruiker kosten? Dus ja, ik bedoelde het in dezelfde tafel op te slaan.


Deze Q&A is automatisch vertaald vanuit de Engelse taal.De originele inhoud is beschikbaar op stackexchange, waarvoor we bedanken voor de cc by-sa 3.0-licentie waaronder het wordt gedistribueerd.
Loading...