Hallo! Wenn Sie Tech-News verfolgen, haben Sie vielleicht schon von dem Okta Bcrypt-Vorfall (Quelle) gehört, der am 1. November gemeldet wurde. Die TLDR des Vorfalls lautete wie folgt:
Der Bcrypt-Algorithmus wurde verwendet, um den Cache-Schlüssel zu generieren, bei dem wir eine kombinierte Zeichenfolge aus Benutzer-ID + Benutzername + Passwort hashen. Unter bestimmten Bedingungen, die unten aufgeführt sind, kann dies Benutzern die Authentifizierung ermöglichen, indem sie den Benutzernamen mit dem gespeicherten Cache-Schlüssel einer vorherigen erfolgreichen Authentifizierung angeben.
Das bedeutet, dass bei einem Benutzernamen von mehr als 52 Zeichen jedes Passwort für die Anmeldung ausreichen würde. Wenn der Benutzername beispielsweise 50 Zeichen lang ist, bedeutet dies, dass der böswillige Akteur nur die ersten 3 Zeichen erraten muss, um einzudringen, was heutzutage für die Computer eine ziemlich triviale Aufgabe ist. Schade, nicht wahr?
Auf der anderen Seite sind solch lange Benutzernamen nicht sehr üblich, was ich zustimme. Einige Unternehmen verwenden jedoch gerne den vollständigen Namen des Mitarbeiters als E-Mail-Adresse. Nehmen wir also an, Albus Percival Wulfric Brian Dumbledore, ein Schulleiter von Hogwarts, sollte besorgt sein, ebenso wie 55 Zeichen: albus.percival.wulfric.brian.dumbledore@hogwarts.school

Dies war aufgrund der Natur des Bcrypt-Hashing-Algorithmus möglich, der eine maximal unterstützte Eingabelänge von 72 Zeichen hat (lesen Sie hier mehr), so dass im Okta-Fall die Zeichen über dem Limit bei der Berechnung des Hashes ignoriert und daher nicht in der Vergleichsoperation verwendet wurden. Wir können das zurückentwickeln:
72 - 53 = 19
– Benutzer-ID mit Trennzeichen, falls vorhanden- Auf diese Weise liegt das Passwort außerhalb des Limits von 72 Zeichen und wird daher vom Bcrypt-Algorithmus ignoriert
Es gab jedoch eine Sache, die mich zum Nachdenken brachte: Wenn es eine bekannte Grenze des Algorithmus gibt, warum wird sie dann nicht von den Krypto-Bibliotheken als eine Form der Eingabevalidierung durchgesetzt? Ein einfacher Code reicht aus (if input length > 72 -> return error
). Ich ging davon aus, dass sie möglicherweise eine benutzerdefinierte Bibliothek für die Bcrypt-Implementierung verwendet und einfach die Eingabevalidierung vergessen haben, was passieren kann. Also beschloss ich, zu überprüfen, wie sich andere Programmiersprachen verhalten.
Go und Bcrypt
Beginnen wir mit Go und implementieren wir den Okta-Vorfall-ähnlichen Fall mit Hilfe der offiziellen Bibliothek: golang.org/x/crypto/bcrypt
package main
import (
"crypto/rand"
"encoding/base64"
"fmt"
"golang.org/x/crypto/bcrypt"
)
func main() {
// 18 + 55 + 1 = 74, so above 72 characters' limit of BCrypt
userId := randomString(18)
username := randomString(55)
password := "super-duper-secure-password"
combinedString := fmt.Sprintf("%s:%s:%s", userId, username, password)
combinedHash, err := bcrypt.GenerateFromPassword([]byte(combinedString), bcrypt.DefaultCost)
if err != nil {
panic(err)
}
// let's try to break it
wrongPassword := "wrong-password"
wrongCombinedString := fmt.Sprintf("%s:%s:%s", userId, username, wrongPassword)
err = bcrypt.CompareHashAndPassword(combinedHash, []byte(wrongCombinedString))
if err != nil {
fmt.Println("Password is incorrect")
} else {
fmt.Println("Password is correct")
}
}
func randomString(length int) string {
bytes := make([]byte, length)
_, err := rand.Read(bytes)
if err != nil {
panic(err)
}
return base64.URLEncoding.EncodeToString(bytes)[:length]
}
Was dieser Code tut, ist:
- Generiert eine 18 Zeichen lange userId
- Generiert einen 55-stelligen Benutzernamen
- verkettet sie miteinander und mit einem Dummy-Passwort unter Verwendung von als Trennzeichen:
super-duper-secure-password
- Berechnet den Bcrypt-Hash aus der verketteten Zeichenkette
- verkettet dann dieselbe Benutzer-ID und denselben Benutzernamen mit einem anderen Passwort:
wrong-password
- verwendet die bcrypt-API, um zu vergleichen, ob die 2. verkettete Zeichenkette mit dem Hash der 1. übereinstimmt
Lassen Sie uns den Code ausführen und das Ergebnis sehen:
panic: bcrypt: password length exceeds 72 bytes
goroutine 1 [running]:
main.main()
20250121-bcrypt-api/01-bcrypt-in-go/main.go:20 +0x2d1
Gut gemacht, los! Wenn wir den Quellcode der Funktion überprüfen, sehen wir diesen Code ganz am Anfang: bcrypt.GenerateFromPassword(...)
if len(password) > 72 {
return nil, ErrPasswordTooLong
}
Perfekt! An diesem Punkt wurde ich noch misstrauischer gegenüber dem von Okta verwendeten Tool, da es so schien, als hätte die Branche das anhand dieses Beispiels herausgefunden. Spoiler-Alarm: So einfach ist es nicht.
Fahren wir mit Java fort.
Java und Bcrypt
Java unterstützt Bcrypt nicht von seiner Kern-API, aber meine einfache Google-Suche zeigte, dass die Spring Security-Bibliothek es implementiert hat. Für diejenigen, die sich nicht für das Java-Ökosystem interessieren, ist Spring das am häufigsten verwendete und kampferprobte Framework, das Bibliotheken für fast alles bietet: Web, DBs, Cloud, Sicherheit, KI usw. Ziemlich mächtiges Tool, das ich in der Vergangenheit viel benutzt habe und immer noch manchmal für meine Nebenprojekte verwende.
Spring Security
Also habe ich dem Projekt die neueste Version von Spring Security hinzugefügt und das gleiche Szenario reproduziert, wie im obigen Go-Beispiel:
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.security.crypto.bcrypt.BCrypt;
public class BcriptSpringSecurity {
public static void main(String[] args) {
// 18 + 55 + 1 = 74, so above 72 characters' limit of BCrypt
var userId = RandomStringUtils.randomAlphanumeric(18);
var username = RandomStringUtils.randomAlphanumeric(55);
var password = "super-duper-secure-password";
var combinedString = String.format("%s:%s:%s", userId, username, password);
var combinedHash = BCrypt.hashpw(combinedString, BCrypt.gensalt());
// let's try to break it
var wrongPassword = "wrong-password";
var wrongCombinedString = String.format("%s:%s:%s", userId, username, wrongPassword);
if (BCrypt.checkpw(wrongCombinedString, combinedHash)) {
System.out.println("Password is correct");
} else {
System.out.println("Password is incorrect");
}
}
}
Ich habe den Code ausgeführt und zu meiner großen Überraschung folgendes Ergebnis gesehen:
Password is correct
Ein Blick auf den Implementierungscode und ich war enttäuscht: obwohl es eine Reihe von Überprüfungen auf Salt gibt:
if (saltLength < 28) {
throw new IllegalArgumentException("Invalid salt");
}
...
if (salt.charAt(0) != '$' || salt.charAt(1) != '2') {
throw new IllegalArgumentException("Invalid salt version");
}
...
minor = salt.charAt(2);
if ((minor != 'a' && minor != 'x' && minor != 'y' && minor != 'b') || salt.charAt(3) != '$') {
throw new IllegalArgumentException("Invalid salt revision");
}
...
Ich habe keine Validierung der Eingabe gesehen, die gehasht wird. Hm…
Ich beschloss, andere Google-Ergebnisse zu überprüfen, und die nächste Java-Bibliothek in der Liste war von Patrick Favre (Link zum GitHub-Repository) mit 513 Starts und der letzten Release-Version 0.10.2 (also nicht stabil) vom 12. Februar 2023 (fast 2 Jahre alt). Dies deutete darauf hin, dass ich es nicht in der Produktion verwenden würde, aber warum nicht unsere Tests durchführen sollte.
Bcrypt von Patrick Favre
import at.favre.lib.crypto.bcrypt.BCrypt;
import org.apache.commons.lang3.RandomStringUtils;
public class BcryptAtFavre {
public static void main(String[] args) {
// 18 + 1 + 55 = 74, so above 72 characters' limit of BCrypt
var userId = RandomStringUtils.randomAlphanumeric(18);
var username = RandomStringUtils.randomAlphanumeric(55);
var password = "super-duper-secure-password";
var combinedString = String.format("%s:%s:%s", userId, username, password);
var combinedHash = BCrypt.withDefaults().hashToString(12, combinedString.toCharArray());
// let's try to break it
var wrongPassword = "wrong-password";
var wrongCombinedString = String.format("%s:%s:%s", userId, username, wrongPassword);
var result = BCrypt.verifyer().verify(combinedHash.toCharArray(), wrongCombinedString);
if (result.verified) {
System.out.println("Password is correct");
} else {
System.out.println("Password is incorrect");
}
}
}
Lassen Sie es uns ausführen:
Exception in thread "main" java.lang.IllegalArgumentException: password must not be longer than 72 bytes plus null terminator encoded in utf-8, was 102
at at.favre.lib.crypto.bcrypt.LongPasswordStrategy$StrictMaxPasswordLengthStrategy.innerDerive(LongPasswordStrategy.java:50)
at at.favre.lib.crypto.bcrypt.LongPasswordStrategy$BaseLongPasswordStrategy.derive(LongPasswordStrategy.java:34)
at at.favre.lib.crypto.bcrypt.BCrypt$Hasher.hashRaw(BCrypt.java:303)
at at.favre.lib.crypto.bcrypt.BCrypt$Hasher.hash(BCrypt.java:267)
at at.favre.lib.crypto.bcrypt.BCrypt$Hasher.hash(BCrypt.java:229)
at at.favre.lib.crypto.bcrypt.BCrypt$Hasher.hashToString(BCrypt.java:205)
at BcryptAtFavre.main(BcryptAtFavre.java:14)
Gut, gut gemacht, Patrick, du hast Java den Tag gerettet!
Nachdem ich den Quellcode überprüft hatte, fand ich dieses Stück:
@Override
public byte[] derive(byte[] rawPassword) {
if (rawPassword.length >= maxLength) {
return innerDerive(rawPassword);
}
return rawPassword;
}
Und die strikte Strategie, die die Ausnahme auslöste, die wir gesehen haben:
final class StrictMaxPasswordLengthStrategy extends BaseLongPasswordStrategy {
StrictMaxPasswordLengthStrategy(int maxLength) {
super(maxLength);
}
@Override
public byte[] innerDerive(byte[] rawPassword) {
throw new IllegalArgumentException("password must not be longer than " + maxLength + " bytes plus null terminator encoded in utf-8, was " + rawPassword.length);
}
}
Wir können sehen, dass diese strikte Strategie als Teil der Standardkonfigurationen verwendet wird:
public static Hasher withDefaults() {
return new Hasher(Version.VERSION_2A, new SecureRandom(), LongPasswordStrategies.strict(Version.VERSION_2A));
}
Cool!
Wechseln wir zu JavaScript.
JavaScript und Bcrypt
Hier habe ich das bcryptjs verwendet, das basierend auf den NPM-Statistiken über 2 Millionen wöchentliche Downloads hat.
const bcrypt = require('bcryptjs')
function randomString (length) {
const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
let result = ''
for (let i = length; i > 0; --i) {
result += chars[Math.floor(Math.random() * chars.length)]
}
return result
}
function runTest () {
// 18 + 55 + 1 = 74, so above 72 characters' limit of BCrypt
const userId = randomString(18)
const username = randomString(55)
const password = 'super-duper-secure-password'
const combinedString = `${userId}:${username}:${password}`
const combinedHash = bcrypt.hashSync(combinedString)
// let's try to break it
const wrongPassword = 'wrong-password'
const wrongCombinedString = `${userId}:${username}:${wrongPassword}`
if (bcrypt.compareSync(wrongCombinedString, combinedHash)) {
console.log('Password is correct')
} else {
console.log('Password is wrong')
}
}
runTest()
Die Ausgabe lautet:
Password is correct
Nicht großartig. Der Quellcode zeigt, dass die Bibliothek, ähnlich wie Spring Security, das Salt validiert
if (salt.charAt(0) !== '$' || salt.charAt(1) !== '2') {
err = Error("Invalid salt version: "+salt.substring(0,2));
if (callback) {
nextTick(callback.bind(this, err));
return;
}
else
throw err;
}
...
aber nicht die Eingabelänge.
Versuchen wir, ob Python es besser kann.
Python und Bcrypt
Die Verwendung der bcrypt-Bibliothek mit 1.3k beginnt und die neueste Version ist im November.
import random
import string
import bcrypt
def random_string(length):
return ''.join(random.choice(string.ascii_letters) for i in range(length))
if __name__ == '__main__':
# 18 + 55 + 1 = 74, so above 72 characters' limit of BCrypt
user_id = random_string(18)
username = random_string(55)
password = "super-duper-secure-password"
combined_string = "{0}:{1}:{2}".format(user_id, username, password)
combined_hash = bcrypt.hashpw(combined_string.encode('utf-8'), bcrypt.gensalt())
# let's try to break it
wrong_password = "wrong-password"
wrong_combined_string = "{0}:{1}:{2}".format(user_id, username, wrong_password)
if bcrypt.checkpw(wrong_combined_string.encode('utf-8'), combined_hash):
print("Password is correct")
else:
print("Password is incorrect")
Das Ergebnis ist das gleiche, das wir bei den meisten unserer Probanden beobachtet haben:
Password is correct
In Ordnung, aber was ist mit einer neueren und sicherheitsorientierteren Sprache – versuchen wir es mit Rust.
Rust und Bcrypt
Als Bibliothek habe ich rust-bcrypt verwendet, basierend auf dem Rat meines KI-Freundes.
use rand::RngCore;
use base64::{Engine as _, engine::general_purpose::URL_SAFE};
use std::error::Error;
fn random_string(length: usize) -> String {
let mut bytes = vec![0u8; length];
rand::thread_rng().fill_bytes(&mut bytes);
URL_SAFE.encode(&bytes)[..length].to_string()
}
fn main() -> Result<(), Box<dyn Error>> {
// 18 + 55 + 1 = 74, so above 72 characters' limit of BCrypt
let user_id = random_string(18);
let username = random_string(55);
let password = "super-duper-secure-password";
let combined_string = format!("{}:{}:{}", user_id, username, password);
let combined_hash = bcrypt::hash(combined_string.as_bytes(), bcrypt::DEFAULT_COST)?;
// let's try to break it
let wrong_password = "wrong-password";
let wrong_combined_string = format!("{}:{}:{}", user_id, username, wrong_password);
match bcrypt::verify(wrong_combined_string.as_bytes(), &combined_hash) {
Ok(true) => println!("Password is correct"),
Ok(false) => println!("Password is incorrect"),
Err(e) => println!("{}", e),
}
Ok(())
}
Die Ausgabe lautet:
Password is correct
Ich kann die Bestätigung der Kosten sehen:
if !(MIN_COST..=MAX_COST).contains(&cost) {
return Err(BcryptError::CostNotAllowed(cost));
}
aber nicht des Inputs. Und hier ist die Stelle, an der die explizite Kürzung von 72 Zeichen erfolgt (der Kommentar stammt aus dem Quellcode der Bibliothek):
// We only consider the first 72 chars; truncate if necessary.
// `bcrypt` below will panic if len > 72
let truncated = if vec.len() > 72 {
if err_on_truncation {
return Err(BcryptError::Truncation(vec.len()));
}
&vec[..72]
} else {
&vec
};
let output = bcrypt::bcrypt(cost, salt, truncated);
Warum?
Das war meine erste Frage, nachdem ich gesehen hatte, dass die meisten Tools dem Muster folgen, das zu der Schwachstelle führt. Der Wikipedia-Artikel über Bcrypt gab einen Hinweis:
Viele Implementierungen von bcrypt kürzen das Passwort auf die ersten 72 Bytes, nach der OpenBSD-Implementierung
Interessant! Schauen wir uns die OpenBSD-Implementierung dieses Algorithmus an, und hier ist der Link dazu. Hier liegt der erste interessante Punkt:
/* strlen() returns a size_t, but the function calls
* below result in implicit casts to a narrower integer
* type, so cap key_len at the actual maximum supported
* length here to avoid integer wraparound */
key_len = strlen(key);
if (key_len > 72)
key_len = 72;
key_len++;
Und von diesem Moment an wird es als Limit verwendet, um über die darin enthaltene Eingabezeichenfolge zu iterieren, zum Beispiel: key_len
u_int32_t
Blowfish_stream2word(const u_int8_t *data, u_int16_t databytes,
u_int16_t *current)
{
u_int8_t i;
u_int16_t j;
u_int32_t temp;
temp = 0x00000000;
j = *current;
for (i = 0; i < 4; i++, j++) {
if (j >= databytes)
j = 0;
temp = (temp << 8) | data[j];
}
*current = j;
return temp;
}
Dabei wird als Parameter key_lengthdatabytes
übergeben. Also dieser Code:
if (j >= databytes)
j = 0;
stellt sicher, dass keine Zeichen, die den Grenzwert (72) überschreiten, verarbeitet werden.
Git blame zeigt, dass die Zeile 11 Jahre alt ist: if (key_len > 72)

Obwohl er 28 Jahre alt ist (womit hast du dich 1997 beschäftigt, ah?) if (j >= databytes) j = 0;

Es ist also schon eine Weile her, dass die API reviewt wurde.
Ein paar Gedanken zu Okta Bcrypt-Vorfall
Mein ursprüngliches Ziel war es, Probleme für jede der genannten Bibliotheken zu erstellen, aber ich habe festgestellt, dass dieses Verhalten bereits an jede von ihnen gemeldet wurde:
- https://github.com/spring-projects/spring-security/issues/15725
- https://github.com/dcodeIO/bcrypt.js/issues/102
- https://github.com/pyca/bcrypt/issues/691
- https://github.com/Keats/rust-bcrypt/issues/87
Überprüfen Sie die Diskussionen und ihre Ergebnisse, indem Sie diesen Links folgen.
Gedanken und Lehren
Als jemand, der einige Jahre seiner Karriere damit verbracht hat, Tools und Lösungen zu entwickeln, die von anderen Software-Ingenieuren verwendet werden können, verstehe ich die Frustration: Sie haben Ihre Zeit und Mühe in das Schreiben einer klaren Dokumentation und Anleitungen investiert, aber eine bestimmte Anzahl Ihrer Benutzer macht sich überhaupt nicht die Mühe, sie zu überprüfen, und verwendet das Tool einfach so, wie sie es für richtig halten. Das ist jedoch die Realität, die ich akzeptieren musste, und ich begann darüber nachzudenken, wie ich meine Tools für diese Anwendungsfälle einsetzen kann. Hier sind ein paar Prinzipien, die ich mir dabei ausgedacht habe.
Lassen Sie nicht zu, dass die Leute Ihre API falsch verwenden
Meiner Meinung nach ist der Ansatz, bei dem das Tool den Teil der Eingabe stillschweigend abschneidet und nur den restlichen verarbeitet, aus der API-Perspektive eine äußerst schlechte Designentscheidung. Was die Sache noch schlimmer macht, ist die Tatsache, dass Bcrypt im Bereich der Sicherheit und sensibler Daten verwendet wird und, wie wir sehen können, die meisten der oben genannten Tools als Name des Eingabeparameters der Hashing-Methode verwenden. Das gute Design sollte die ungültige Eingabe von password mit dem Fehler / der Ausnahme / jedem anderen Mechanismus, den die Plattform verwendet, explizit ablehnen. Also im Grunde genau das, was Go und Patricks Java-Bibliothek getan haben. Auf diese Weise wären Vorfälle wie Okta one von vornherein unmöglich (übrigens, ich schiebe die Schuld nicht von Okta weg, wenn man bedenkt, in welchem Bereich sie tätig sind).
Es ist jedoch in Ordnung, die nicht standardmäßige unsichere Option anzubieten, die es den Benutzern ermöglicht, längere Eingaben zu übergeben, die abgeschnitten werden, wenn der Benutzer explizit danach fragt. Ein Präfix/Suffix wie unsafe, truncated usw. kann eine gute Ergänzung zu den Namen der Methode sein, die diese Optionen verfügbar macht.
Berechenbar sein
Wenn wir einen Schritt zurück vom Bcrypt-Fall gehen, stellen Sie sich andere Beispiele vor, wenn ein solches Muster in der Branche üblich wird:
- Wir haben ein neues Benutzerkonto bei HBO erstellt, um eine neue Staffel von Rick and Morty zu sehen, und es gibt eine Warnung, dass die maximale Größe des Passworts 18 Zeichen nicht überschreiten sollte. Der Passwort-Generator Ihres Passwort-Manager-Tools verwendet jedoch 25 Zeichen als Standardlänge des erzeugten Passworts. Der Passwort-Manager fügt dieses Passwort also beim Erstellen eines Kontos ein, aber der Server schneidet die letzten 7 Zeichen ab, hasht den Rest und speichert den Hash in der Datenbank. Wie einfach wäre es für uns, uns das nächste Mal bei HBO einzuloggen und eine neue Folge zu sehen?
- Der technische Leiter des neuen Projekts hat ein Linter-Tool konfiguriert und die maximale Zeilenlänge auf 100 Zeichen festgelegt. Während einer Prüfung entfernt Linter die Zeichen über dem definierten Grenzwert und informiert darüber, dass die Prüfung bestanden wurde. Wie nützlich wäre es?
Ein gutes API-Design sollte sich daran erinnern, dass niemand Überraschungen mag, wenn es um Technologie geht.
Kein Ego
Als ich ein paar Online-Diskussionen über den Bcrypt Okta-Vorfall verfolgte, fiel mir noch etwas anderes auf: Während sich die Mehrheit der Kommentare einig war, dass wir APIs wie diese besser gestalten sollten, gab es ein paar Leute, die eine sehr defensive Haltung einnahmen und ihr Ego entblößten: „Lesen Sie ein Papier, bevor Sie etwas verwenden!“, „APIs korrigieren nur die Eingabe nach den dummen Benutzern!“, etc. Meiner Erfahrung nach ist das Ego ein großer Feind des Ingenieurwesens. Und es würde mich nicht wundern, wenn Sie auch in dieser Hinsicht die eine oder andere Geschichte haben. Also, ja, lassen Sie uns unsere Egos nicht in unsere APIs einbringen.
Seien Sie hilfreich
Verstehen Sie mich nicht falsch, ich verstehe das Wesentliche, dass die Benutzer einige Grundkenntnisse haben sollten, bevor sie ein Tool verwenden. Doch zurück zur Realität: Wie viele verschiedene Tools, Programmiersprachen, Datenbanken, Protokolle, Frameworks, Bibliotheken, Algorithmen, Datenstrukturen, Clouds, KI-Modelle etc. nutzt ein Software-Ingenieur heutzutage pro Woche? Ich habe versucht, für meinen Anwendungsfall zu zählen, habe aber aufgehört, nachdem die Zahl 30 erreicht hatte. Ist es möglich, sie alle tief zu kennen? Um alle Grenzfälle und Grenzen zu kennen? Für einige von ihnen und bis zu einem gewissen Grad ist es eine vernünftige Frage, ebenso wie eine Expertise in 1 oder 2, aber definitiv nicht in allen. Die harte Wahrheit ist, dass die Branche heute im Durchschnitt ein breites Spektrum an Wissen über das tiefe Wissen benötigt (überprüfen Sie alle Stellenangebote, um diese Behauptung zu überprüfen). Warum also nicht bei der Entwicklung der Tools unseren Kollegen helfen? Wenn unser Tool zum Beispiel nur positive Zahlen akzeptiert, fügen wir unsere Lösung hinzu und machen das Leben für jemanden da draußen einfacher: if num < 1 -> return error
Vor allem, wenn das Tool im sicherheitssensiblen Kontext eingesetzt werden kann, in dem der Mensch in der Regel die Schwachstelle bei der Thread-Modellierung ist. Die gute API kann da helfen.
Sei mutig
Es kommt nicht so oft vor, dass die API, die wir entwerfen, etwas völlig Neues auf der Welt ist. Höchstwahrscheinlich gibt es andere Lösungen wie unsere. Und die Chancen stehen gut, dass sie bestimmte Dinge bereits auf eine bestimmte Art und Weise getan haben. Das bedeutet jedoch nicht, dass wir den gleichen Weg gehen müssen. Ein großes Lob an das Go-Team und Patricks Java-Bibliothek, die mutig waren, die Dinge anders zu machen, als es die Branche im Bcrypt-Beispiel tut. Lassen Sie uns von ihnen lernen.
Wiederholen
Unabhängig von den ursprünglichen Designentscheidungen und -absichten ist es nie zu spät, einige von ihnen zu wiederholen, wenn wir einen Bedarf sehen oder neue Informationen entdeckt haben. Das ist tatsächlich ein Punkt, an dem viele von uns aus verschiedenen Gründen scheitern, von denen einige oben aufgeführt sind.
Fazit
Der Okta Bcrypt-Vorfall hat große Sicherheitsprobleme aufgedeckt. Unser Test hat gezeigt, dass die Branche auch 5 Monate nach dem Vorfall immer noch anfällig für das gleiche Ergebnis ist, so dass die Chancen groß sind, dass noch mehr kommen wird. Als Softwareentwickler können wir jedoch daraus lernen und diese Lektionen bei der Entwicklung von APIs anwenden, um sie vorhersehbar und benutzerfreundlicher zu machen.
Weiterer interessanter Beitrag: LLM mit 2 Milliarden Parametern: Erstellen mit Python