tl; dr:
Es ist nicht möglich, so etwas wirklich sicher zu machen, aber es kann "wahrscheinlich gut genug" gemacht werden, um brauchbar und akzeptabel zu sein
Bei Ihren Optionen handelt es sich im Grunde genommen um eine Form von verschlüsseltem Speicher (mit dem Risiko, dass Verschlüsselungsschlüssel gestohlen werden, da diese zur Entschlüsselung vorhanden sein müssen) oder um Hashing mit den bekannten Problemen des Hashing Passwörter (eine Kreditkartennummer ist im Grunde ein "Passwort").
Ich würde dies als zweistufiges System implementieren, bei dem die erste Ebene ein einfacher CRC32 und die zweite Ebene ein Vielfaches wäre iterierte sichere Hash-Funktion. Ja, CRC32 ist kein kryptografisch sicherer Hash, aber das spielt in diesem speziellen Fall keine Rolle, da der CRC nicht das schwache Glied ist.
Wenn der Gedanke, einen nicht kryptografisch zu verwenden, Ein sicherer Algorithmus macht Ihnen zu viel Angst. Sie können den CRC dennoch durch einen kryptografisch gesicherten Algorithmus ersetzen und nur z Die niedrigstwertigen 32 (oder 16, für einen größeren Rand) Bits aus dem resultierenden Hash.
Der Grund für diesen Ansatz ist, dass der Bereich möglicher Eingaben nur etwa 39 Bits [1] . Es ist praktisch unmöglich, diesen Schlüsselraum auf wirklich sichere Weise zu hashen, während das System für die vorgesehene Verwendung betriebsbereit bleibt.
Ein Brute-Force-Angriff auf einen 39-Bit-Schlüsselraum ist nicht nur theoretisch machbar, sondern auch recht trivial - es sei denn Jede einzelne Operation ist extrem teuer.
Die Hauptbedrohung, gegen die Sie sich verteidigen müssen, ist der Diebstahl Ihrer Datenbank, gefolgt vom brutalen Erzwingen, dass Ihre Hashes gültige Kartennummern abrufen. Das nächstbeste, was ein Angreifer tun könnte, wäre online abzufragen, ob eine unbekannte Nummer, die mit einer zufällig übermittelten Nummer identisch ist, zuvor verwendet wurde, oder ob eine bereits bekannte gültige Nummer wurde verwendet (keines ist jedoch sehr nützlich!).
Kreditkarten sind normalerweise 5 Jahre gültig. Damit das System sicher ist, muss es mindestens 5 Jahren Brute-Force standhalten. Mit anderen Worten, die für eine einzelne Überprüfung ausgeführte Arbeit muss so rechenintensiv sein, dass eine dedizierte Crackmaschine mit mehreren GPUs nicht mehr als 2 ^ 39 / (5 * 365 * 86400) = 3486,5 Überprüfungen pro Sekunde ausführen kann.
Unter Berücksichtigung der bekannten Zahl von 348 Milliarden pro Sekunde aus dem Jahr 2012 müsste der einzige wirklich sichere Ansatz den Wert von mindestens 100 Millionen Hashing speichern. Unter Berücksichtigung des Mooreschen Gesetzes wären das inzwischen 200 Millionen, und wir ziehen nicht einmal die Möglichkeit in Betracht, dass jemand zwei oder drei solcher Maschinen (oder vielleicht zehn) besitzt.
Dies ist jedoch still berücksichtigt nicht die Tatsache, dass Banken von Natur aus dumm sind und erhöht einfach die vorletzte Ziffer für eine neue gültige Nummer (und aktualisiert die Prüfziffer). Alle meine in den letzten 20 Jahren ausgestellten Kreditkarten hatten dieselbe Nummer, mit Ausnahme der vorletzten Ziffer, die 0, 1, 2, 3, ... erhöht.
Dies bedeutet, dass die Planung für 5 Jahre noch erfolgt ist nicht genug . Jemand, der eine abgelaufene Kreditkartennummer kennt, kann trivial die gültige Nummer der Follower-Karte ableiten. Sie müssen daher eher für so etwas wie 30 Jahre planen, nicht 5 Jahre. Ich überlasse die Extrapolation von Moores Gesetz auf weitere 20 bis 30 Jahre für Hausaufgaben.
Damit das System wirklich, wirklich sicher ist, müsste Ihr Server das ausführen Dies entspricht einer Billion Hashes (oder mehr) pro Überprüfung, die mit einer Rate von beispielsweise 10 Millionen pro Sekunde für eine typische CPU-Implementierung mehr als einen Tag in Anspruch nehmen würden. Mit anderen Worten, das System ist für den vorgesehenen Zweck vollständig unbrauchbar.
Es wird etwas benötigt, das mehrere Größenordnungen schneller ist. Die meisten Abfragen sind negative Abfragen, und ein einfacher, schneller Hash könnte verwendet werden, um 99,9% aller Negative zu entfernen, wenn dies die ohnehin schwache Sicherheit nicht noch schwächer macht. Hier kommt CRC32 ins Spiel.
Wenn die CRC32 von zwei Kreditkartennummern nicht übereinstimmen, ist garantiert, dass die Nummern nicht identisch sind. Meistens ist dies der Fall und Sie können sofort "Nein!" Zurückgeben. Sie können 99,9% der Arbeit überspringen, ohne etwas preiszugeben.
Wenn die CRCs übereinstimmen übereinstimmen, ist dies möglicherweise ein Treffer, es besteht jedoch die Möglichkeit einer Hash-Kollision. Nun wird der sichere kryptografische Hash (der mindestens 160, besser 256 Bit haben würde) berechnet und verglichen. Die Wahrscheinlichkeit einer Kollision ist jetzt vernachlässigbar. Wenn der Hash übereinstimmt, ist es sicher, dass die Anzahl übereinstimmt.
CRC32 enthält 32 Informationsbits. Es ist unmöglich , 39 Bit Informationen aus 32 Bit wiederherzustellen, unabhängig davon, welche Rechenressourcen Sie besitzen. Daher ist die Verwendung des CRC in diesem Fall sicher (oder zumindest nicht weniger sicher als alles andere).
Wie von Ben Voigt hervorgehoben, handelt es sich um Natürlich ist es immer noch möglich, die Informationen zu erraten, die nicht wiederhergestellt werden können, und 7 zu erratende Bits sind keine schreckliche Menge (durch Verketten des Ablaufdatums werden diese 15 Bits erreicht). Das stimmt, aber Sie können nicht viel dagegen tun.
Was ist überhaupt mit CRC und Sicherheit? CRC ist nicht kryptografisch sicher. Es ist relativ einfach, Bits zu manipulieren, um eine gewünschte Ausgabe zu erhalten (hier kein Problem, wäre dies bei Anmeldungen), und die Funktion kann trivial umgekehrt werden (4 Tabellensuchen plus ein paar Verschiebungen und xor) auf eine 32-Bit-Eingabe. ein etwas größeres Problem. Zum Glück, aber dieses Bitmuster ist ziemlich wertlos, da es weder eine gültige Zahl noch eine Teilmenge eines 39-Bit-Musters ist, das eine gültige Zahl sein könnte (außer durch Zufall).
Das brutale Erzwingen des gesamten 39-Bit-Schlüsselraums ist einfacher als der Versuch, Streiche auf dem CRC zu spielen, da dies leider einfach und schnell ist: Eine SSE4.2-Implementierung benötigt ungefähr einen halben Zyklus pro Byte (also) 2 Zyklen pro Hash), was bedeutet, dass ein Desktop-Computer den gesamten Schlüsselbereich in ein oder zwei Sekunden ausführen kann (vorausgesetzt, die Schlüssel werden mit allen in L1 passenden verglichen).
Die umfassende Suche würde alle 39-Bit-Daten anzeigen Muster mit demselben CRC, was bedeutet, dass es sich möglicherweise um Kreditkartennummern handeln kann. Mit dem Luhn-Algorithmus kann der Angreifer sofort 9 von 10 nicht gültigen Nummern verwerfen. Das ist zwar schlecht, aber es ist wirklich nur eine Folge davon, dass nicht zu viele Eingabemöglichkeiten vorhanden sind und eine Prüfziffer oben implantiert ist!
Trotzdem ist der CRC tatsächlich stärker Dieses Szenario ist ein kryptografisch sicherer Algorithmus: Angesichts der weltweit im Umlauf befindlichen 2-3 Milliarden Kreditkarten liegt die Wahrscheinlichkeit einer Kollision mit einem 160-Bit-Hash zwischen 1 und 10 20 sup> und nicht einmal Denken Sie über die Chancen nach, einen 256-Bit-Hash zu verwenden. Dies bedeutet, dass jeder Treffer während Ihrer umfassenden Suche im 39-Bit-Schlüsselbereich sofort Ihnen die einzig garantierte gültige Kartennummer gibt. Ein Treffer auf dem CRC32 gibt Ihnen nur eine von vielen möglichen Zahlen.
Eine Sache, die Sie tun könnten, um Geschwindigkeit gegen Sicherheit einzutauschen, wäre, einige Informationen weiter von der zu entfernen CRC Zum Beispiel könnten Sie einfach die höchstwertigen 8 oder 16 Bits des CRC verwerfen, wodurch diese zu den Bits hinzugefügt werden, die ein Angreifer erraten muss. Dies wird natürlich die Wirksamkeit des Schnittes etwas verringern, aber nicht zu drastisch. Anstatt 99,99% der Arbeit zu beschneiden, könnten Sie am Ende 99% oder 98% beschneiden, was immer noch sehr gut ist.
Die zweite Verifizierungsebene muss, wie oben angegeben, ein kryptografisch sicherer Hash sein, der mindestens eine Million Iterationen ausführt, ähnlich wie bei einem Schlüssel-Stretching-Schema (tatsächlich benötigt er viel mehr als das , aber das System muss auch praktisch verwendbar bleiben.
Der Implementierer muss hier das Risiko gegen die Verwendbarkeit austauschen. Ein Server sollte mindestens noch in der Lage sein, ein paar Dutzend Anforderungen pro zu verarbeiten zweite. Kunden / Händler stimmen nicht zu, wenn das Nachschlagen einer Nummer mehrere Minuten (oder länger) dauert, unabhängig von den Auswirkungen auf die Sicherheit. Es ist auch nicht praktisch, mehr oder weniger einen dedizierten Server pro Händler zu haben.
Da das Abgleichen nur auf Händlerbasis interessant ist, könnte man ein Salz pro Händler konstant verwenden und Kartennummern redundant speichern zusammen mit einem Index der Händler-ID, der in den Zuständigkeitsbereich eines vernünftigen Datenbanksystems fallen sollte.
[1] Eine Kreditkartennummer besteht aus 16 Ziffern wobei die letzte eine von den anderen abgeleitete Prüfsumme ist (Luhn-Algorithmus). Die vorletzte Ziffer ist normalerweise (nicht unbedingt, aber normalerweise) die fortlaufende Kartennummer, beginnend bei Null für die erste Karte des Kontoinhabers, 1 für den Ehepartner oder eine Ersatzkarte, 2 für die nächste Karte danach und so weiter Die ersten drei Ziffern kodieren den Kartenaussteller und die Bank und verwenden nur etwa die Hälfte der möglichen Anzahl dreistelliger Kombinationen.
Insgesamt bleiben uns also 12 und 13 vollständige Dezimalstellen der Entropie, die liegt irgendwo zwischen etwas mehr als 36 Bit und 39 Bit.
Ich würde empfehlen, das Ablaufdatum mit der Nummer zu verketten, da dies die Situation etwas weniger miserabel macht. Meine Kreditkarten sind immer 5 Jahre gültig (ich bin mir nicht sicher, ob dies die universelle Regel ist, aber ich würde es annehmen). Wenn Sie also das Ablaufdatum hinzufügen, werden 5 * 12 Möglichkeiten oder 5,9 Bit hinzugefügt (diese sind so gut wie kostenlos). da brauchst du die Ablaufdaten sowieso in einer Transaktion!).