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).