mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-15 10:25:11 +00:00
fix(security): prevent TOTP reuse (#12616)
# Which Problems Are Solved TOTP codes could be reused, violating [RFC 6238, section 5.2](https://datatracker.ietf.org/doc/html/rfc6238#section-5.2). # How the Problems Are Solved Transmitted codes are now recorded in each success event. As the codes amount to secrets, they are not stored verbatim but as a randomly salted HMAC-SHA256 (`crypto.HMACValue`). Each value gets a fresh random salt, so an equal code always produces a different stored value and two entries can never be recognized as being derived from the same code. This is deliberately not a replacement for proper secret storage: with the salt stored alongside the hash and a 6 digit payload, anyone with event access can brute-force the code in milliseconds. That is acceptable here because a code is worthless once its window has passed. The `HMACValue` doc comment states the same. TOTP codes are low-entropy (6 digits), pseudo random codes. Therefore it is possible for the same code to be generated more than once over the lifetime of a user. In order to prevent the (unlikely) case where users login with large time intervalls and a generated code may be equal to the one last used a long time ago, we only check for codes used within the recent period window. A simpler implementation would be simply storing the latest consumed step, but the TOTP library does not return this value. Because of the allowed skew there are always 3 steps within the validation window, so we can't calculate the current step based on time alone. The retained history spans one period more than the validation window: validity is decided by the app server's clock, while the stored events carry the database clock, and the extra period absorbs the drift between them. **Note:** a reused code pushes a distinct `user.human.mfa.otp.check.reused` event, not a failed check event. A replay therefore stays observable through the Events API without counting towards the lockout policy. Otherwise anyone who captured a code could replay it to lock the user out. # Additional Changes - Read only the latest events in recheck query # Additional Context - Closes https://github.com/zitadel/zitadel/issues/6452 --------- Co-authored-by: Livio Spring <[email protected]> Co-authored-by: Copilot Autofix powered by AI <[email protected]> Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: muhlemmer <[email protected]>
This commit is contained in:
co-authored by
Livio Spring
Copilot Autofix powered by AI
copilot-swe-agent[bot] <198982749+[email protected]>
muhlemmer
parent
c9d747d407
commit
6128aeaa89
@@ -177,6 +177,7 @@ Errors:
|
||||
NotExisting: "المصادقة متعددة العوامل OTP (كلمة مرور لمرة واحدة) غير موجودة"
|
||||
NotReady: "المصادقة متعددة العوامل OTP (كلمة مرور لمرة واحدة) ليست جاهزة"
|
||||
InvalidCode: "رمز غير صالح"
|
||||
Reused: "تم استخدام هذا الرمز بالفعل. يرجى انتظار رمز جديد"
|
||||
U2F:
|
||||
NotExisting: "U2F غير موجود"
|
||||
Passwordless:
|
||||
@@ -763,6 +764,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "نجح فحص OTP للمصادقة متعددة العوامل"
|
||||
failed: "فشل فحص OTP للمصادقة متعددة العوامل"
|
||||
reused: "أعيد استخدام رمز OTP للمصادقة متعددة العوامل"
|
||||
sms:
|
||||
added: "تمت إضافة OTP SMS للمصادقة متعددة العوامل"
|
||||
removed: "تمت إزالة OTP SMS للمصادقة متعددة العوامل"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Многофакторният OTP (OneTimePassword) не съществува"
|
||||
NotReady: "Многофакторният OTP (OneTimePassword) не е готов"
|
||||
InvalidCode: "Невалиден код"
|
||||
Reused: "Този код вече е използван. Моля, изчакайте нов код"
|
||||
U2F:
|
||||
NotExisting: "U2F не съществува"
|
||||
Passwordless:
|
||||
@@ -763,6 +764,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Многофакторната OTP проверка е успешна"
|
||||
failed: "Многофакторната OTP проверка е неуспешна"
|
||||
reused: "Многофакторният OTP код е използван повторно"
|
||||
sms:
|
||||
added: "Добавен Многофакторната OTP SMS"
|
||||
removed: "Премахнато многофакторно OTP SMS"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Vícefaktorové OTP (OneTimePassword) neexistuje"
|
||||
NotReady: "Vícefaktorové OTP (OneTimePassword) není připraveno"
|
||||
InvalidCode: "Neplatný kód"
|
||||
Reused: "Tento kód již byl použit. Počkejte prosím na nový kód"
|
||||
U2F:
|
||||
NotExisting: "U2F neexistuje"
|
||||
Passwordless:
|
||||
@@ -765,6 +766,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Kontrola OTP pro vícefaktorové ověření byla úspěšná"
|
||||
failed: "Kontrola OTP pro vícefaktorové ověření selhala"
|
||||
reused: "Kód OTP pro vícefaktorové ověření byl použit opakovaně"
|
||||
sms:
|
||||
added: "SMS pro vícefaktorové OTP přidána"
|
||||
removed: "SMS pro vícefaktorové OTP odstraněna"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Multifaktor OTP (OneTimePassword) existiert nicht"
|
||||
NotReady: "Multifaktor OTP (OneTimePassword) ist nicht bereit"
|
||||
InvalidCode: "Code ist ungültig"
|
||||
Reused: "Dieser Code wurde bereits verwendet. Bitte warten Sie auf einen neuen Code"
|
||||
U2F:
|
||||
NotExisting: "U2F existiert nicht"
|
||||
Passwordless:
|
||||
@@ -767,6 +768,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Multifaktor OTP Verifikation erfolgreich"
|
||||
failed: "Multifaktor OTP Verifikation fehlgeschlagen"
|
||||
reused: "Multifaktor OTP Code wiederverwendet"
|
||||
sms:
|
||||
added: "Multifaktor OTP SMS hinzugefügt"
|
||||
removed: "Multifaktor OTP SMS entfernt"
|
||||
|
||||
@@ -178,6 +178,7 @@ Errors:
|
||||
NotExisting: "Multifactor OTP (OneTimePassword) doesn't exist"
|
||||
NotReady: "Multifactor OTP (OneTimePassword) isn't ready"
|
||||
InvalidCode: "Invalid code"
|
||||
Reused: "This code was already used. Please wait for a new code"
|
||||
U2F:
|
||||
NotExisting: "U2F does not exist"
|
||||
Passwordless:
|
||||
@@ -772,6 +773,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Multifactor OTP check succeeded"
|
||||
failed: "Multifactor OTP check failed"
|
||||
reused: "Multifactor OTP code reused"
|
||||
sms:
|
||||
added: "Multifactor OTP SMS added"
|
||||
removed: "Multifactor OTP SMS removed"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Multifactor OTP (OneTimePassword) no existe"
|
||||
NotReady: "Multifactor OTP (OneTimePassword) no está listo"
|
||||
InvalidCode: "Código no válido"
|
||||
Reused: "Este código ya se ha utilizado. Espera a que se genere un nuevo código"
|
||||
U2F:
|
||||
NotExisting: "U2F no existe"
|
||||
Passwordless:
|
||||
@@ -767,6 +768,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Comprobación exitosa de Multifactor OTP"
|
||||
failed: "Comprobación fallida de Multifactor OTP"
|
||||
reused: "Código de Multifactor OTP reutilizado"
|
||||
sms:
|
||||
added: "Multifactor OTP SMS añadido"
|
||||
removed: "Multifactor OTP SMS elimonado"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "OTP multifactoriel (mot de passe à usage unique) n'existe pas."
|
||||
NotReady: "OTP multifactoriel (mot de passe à usage unique) n'est pas prêt."
|
||||
InvalidCode: "Code invalide"
|
||||
Reused: "Ce code a déjà été utilisé. Veuillez attendre un nouveau code"
|
||||
U2F:
|
||||
NotExisting: "L'U2F n'existe pas"
|
||||
Passwordless:
|
||||
@@ -765,6 +766,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Vérification de l'OTP multifactorielle réussie"
|
||||
failed: "La vérification de l'OTP multifactorielle a échoué"
|
||||
reused: "Code OTP multifactoriel réutilisé"
|
||||
sms:
|
||||
added: "Ajout de SMS OTP multifactoriels"
|
||||
removed: "Suppression des SMS OTP multifactoriels"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "A multifaktoros OTP (OneTimePassword) nem létezik"
|
||||
NotReady: "A multifaktoros OTP (OneTimePassword) nincs készen"
|
||||
InvalidCode: "Érvénytelen kód"
|
||||
Reused: "Ezt a kódot már felhasználták. Kérjük, várjon egy új kódra"
|
||||
U2F:
|
||||
NotExisting: "Az U2F nem létezik"
|
||||
Passwordless:
|
||||
@@ -767,6 +768,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "A multifaktoros OTP ellenőrzés sikeres"
|
||||
failed: "A multifaktoros OTP ellenőrzés sikertelen"
|
||||
reused: "A multifaktoros OTP kód újrafelhasználva"
|
||||
sms:
|
||||
added: "Multifaktoros OTP SMS hozzáadva"
|
||||
removed: "Multifaktoros OTP SMS eltávolítva"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "OTP multifaktor (OneTimePassword) tidak ada"
|
||||
NotReady: "OTP multifaktor (OneTimePassword) belum siap"
|
||||
InvalidCode: "Kode tidak valid"
|
||||
Reused: "Kode ini sudah digunakan. Silakan tunggu kode baru"
|
||||
U2F:
|
||||
NotExisting: "U2F tidak ada"
|
||||
Passwordless:
|
||||
@@ -762,6 +763,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Pemeriksaan OTP multifaktor berhasil"
|
||||
failed: "Pemeriksaan OTP multifaktor gagal"
|
||||
reused: "Kode OTP multifaktor digunakan kembali"
|
||||
sms:
|
||||
added: "OTP SMS multifaktor ditambahkan"
|
||||
removed: "OTP SMS multifaktor dihapus"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Multifattore OTP (OneTimePassword) non esistente"
|
||||
NotReady: "Multifattore OTP (OneTimePassword) non è pronto"
|
||||
InvalidCode: "Codice non valido"
|
||||
Reused: "Questo codice è già stato utilizzato. Attendere un nuovo codice"
|
||||
U2F:
|
||||
NotExisting: "U2F non esistente"
|
||||
Passwordless:
|
||||
@@ -766,6 +767,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Controllo OTP riuscito"
|
||||
failed: "Controllo OTP fallito"
|
||||
reused: "Codice OTP riutilizzato"
|
||||
sms:
|
||||
added: "Aggiunta SMS OTP"
|
||||
removed: "SMS OTP rimossa"
|
||||
|
||||
@@ -177,6 +177,7 @@ Errors:
|
||||
NotExisting: "多要素OTP(ワンタイムパスワード)が存在しません"
|
||||
NotReady: "多要素OTP(ワンタイムパスワード)が利用可能でありません"
|
||||
InvalidCode: "無効なコードです"
|
||||
Reused: "このコードはすでに使用されています。新しいコードをお待ちください"
|
||||
U2F:
|
||||
NotExisting: "U2Fは存在しません"
|
||||
Passwordless:
|
||||
@@ -768,6 +769,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "MFA OTPチェックの成功"
|
||||
failed: "MFA OTPチェックの失敗"
|
||||
reused: "MFA OTPコードの再利用"
|
||||
sms:
|
||||
added: "多要素 OTP SMS を追加しました"
|
||||
removed: "多要素 OTP SMS を削除しました"
|
||||
|
||||
@@ -177,6 +177,7 @@ Errors:
|
||||
NotExisting: "다중 요소 OTP(일회용 비밀번호)가 존재하지 않습니다"
|
||||
NotReady: "다중 요소 OTP(일회용 비밀번호)가 준비되지 않았습니다"
|
||||
InvalidCode: "코드가 잘못되었습니다"
|
||||
Reused: "이 코드는 이미 사용되었습니다. 새 코드를 기다려 주세요"
|
||||
U2F:
|
||||
NotExisting: "U2F가 존재하지 않습니다"
|
||||
Passwordless:
|
||||
@@ -768,6 +769,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "다중인증 OTP 확인 성공"
|
||||
failed: "다중인증 OTP 확인 실패"
|
||||
reused: "다중인증 OTP 코드 재사용"
|
||||
sms:
|
||||
added: "다중인증 OTP SMS 추가됨"
|
||||
removed: "다중인증 OTP SMS 삭제됨"
|
||||
|
||||
@@ -175,6 +175,7 @@ Errors:
|
||||
NotExisting: "Мултифактор OTP (Еднократна Лозинка) не постои"
|
||||
NotReady: "Мултифактор OTP (Еднократна Лозинка) не е подготвен"
|
||||
InvalidCode: "Невалиден код"
|
||||
Reused: "Овој код е веќе искористен. Ве молиме почекајте нов код"
|
||||
U2F:
|
||||
NotExisting: "U2F не постои"
|
||||
Passwordless:
|
||||
@@ -762,6 +763,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Проверката на мултифактор OTP е успешна"
|
||||
failed: "Проверката на мултифактор OTP е неуспешна"
|
||||
reused: "Кодот за мултифактор OTP е повторно употребен"
|
||||
sms:
|
||||
added: "Додадена е мултифакторна OTP SMS"
|
||||
removed: "Отстранета мултифакторна OTP SMS"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Multifactor OTP (OneTimePassword) bestaat niet"
|
||||
NotReady: "Multifactor OTP (OneTimePassword) is niet klaar"
|
||||
InvalidCode: "Ongeldige code"
|
||||
Reused: "Deze code is al gebruikt. Wacht op een nieuwe code"
|
||||
U2F:
|
||||
NotExisting: "U2F bestaat niet"
|
||||
Passwordless:
|
||||
@@ -767,6 +768,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Multifactor OTP controle geslaagd"
|
||||
failed: "Multifactor OTP controle mislukt"
|
||||
reused: "Multifactor OTP code hergebruikt"
|
||||
sms:
|
||||
added: "Multifactor OTP SMS toegevoegd"
|
||||
removed: "Multifactor OTP SMS verwijderd"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Wieloskładnikowe OTP (OneTimePassword) nie istnieje"
|
||||
NotReady: "Wieloskładnikowe OTP (OneTimePassword) nie jest gotowe"
|
||||
InvalidCode: "Nieprawidłowy kod"
|
||||
Reused: "Ten kod został już użyty. Poczekaj na nowy kod"
|
||||
U2F:
|
||||
NotExisting: "U2F nie istnieje"
|
||||
Passwordless:
|
||||
@@ -767,6 +768,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Sprawdzenie wielofaktorowego OTP zakończone powodzeniem"
|
||||
failed: "Sprawdzenie wielofaktorowego OTP nie powiodło się"
|
||||
reused: "Kod wielofaktorowego OTP użyty ponownie"
|
||||
sms:
|
||||
added: "Dodano wieloskładnikowy OTP SMS"
|
||||
removed: "Usunięto wieloskładnikowy OTP SMS"
|
||||
|
||||
@@ -175,6 +175,7 @@ Errors:
|
||||
NotExisting: "OTP (OneTimePassword) de autenticação multifator não existe"
|
||||
NotReady: "OTP (OneTimePassword) de autenticação multifator não está pronto"
|
||||
InvalidCode: "Código inválido"
|
||||
Reused: "Este código já foi utilizado. Aguarde um novo código"
|
||||
U2F:
|
||||
NotExisting: "U2F não existe"
|
||||
Passwordless:
|
||||
@@ -762,6 +763,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Verificação de OTP de autenticação multifator bem-sucedida"
|
||||
failed: "Verificação de OTP de autenticação multifator falhou"
|
||||
reused: "Código de OTP de autenticação multifator reutilizado"
|
||||
sms:
|
||||
added: "Adicionado OTP SMS multifator"
|
||||
removed: "OTP SMS multifator removido"
|
||||
|
||||
@@ -177,6 +177,7 @@ Errors:
|
||||
NotExisting: "Multifactor OTP (Parolă Unică) nu există"
|
||||
NotReady: "Multifactor OTP (Parolă Unică) nu este pregătit"
|
||||
InvalidCode: "Cod invalid"
|
||||
Reused: "Acest cod a fost deja utilizat. Vă rugăm să așteptați un cod nou"
|
||||
U2F:
|
||||
NotExisting: "U2F nu există"
|
||||
Passwordless:
|
||||
@@ -763,6 +764,7 @@ Errors:
|
||||
check:
|
||||
succeeded: "Verificarea Multifactor OTP a reușit"
|
||||
failed: "Verificarea Multifactor OTP a eșuat"
|
||||
reused: "Cod Multifactor OTP reutilizat"
|
||||
sms:
|
||||
added: "Multifactor OTP SMS adăugat"
|
||||
removed: "Multifactor OTP SMS șters"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Мультифактор OTP (OneTimePassword) не существует"
|
||||
NotReady: "Мультифактор OTP (OneTimePassword) не готов"
|
||||
InvalidCode: "Неверный код"
|
||||
Reused: "Этот код уже был использован. Пожалуйста, дождитесь нового кода"
|
||||
U2F:
|
||||
NotExisting: "Двухфакторная аутентификация не существует"
|
||||
Passwordless:
|
||||
@@ -756,6 +757,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Проверка мультифактора OTP прошла успешно"
|
||||
failed: "Проверка мультифактора OTP не удалась"
|
||||
reused: "Код мультифактора OTP использован повторно"
|
||||
sms:
|
||||
added: "Добавлен многофакторный OTP SMS"
|
||||
removed: "Удалены многофакторные OTP SMS"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Tvåfaktor OTP (OneTimePassword) finns inte"
|
||||
NotReady: "Tvåfaktor OTP (OneTimePassword) är inte redo"
|
||||
InvalidCode: "Ogiltig kod"
|
||||
Reused: "Den här koden har redan använts. Vänta på en ny kod"
|
||||
U2F:
|
||||
NotExisting: "U2F finns inte"
|
||||
Passwordless:
|
||||
@@ -767,6 +768,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Tvåfaktor OTP-kontroll lyckades"
|
||||
failed: "Tvåfaktor OTP-kontroll misslyckades"
|
||||
reused: "Tvåfaktor OTP-kod återanvänd"
|
||||
sms:
|
||||
added: "Tvåfaktor OTP SMS tillagd"
|
||||
removed: "Tvåfaktor OTP SMS borttagen"
|
||||
|
||||
@@ -177,6 +177,7 @@ Errors:
|
||||
NotExisting: "Çok faktörlü OTP (Tek Kullanımlık Şifre) mevcut değil"
|
||||
NotReady: "Çok faktörlü OTP (Tek Kullanımlık Şifre) hazır değil"
|
||||
InvalidCode: "Geçersiz kod"
|
||||
Reused: "Bu kod zaten kullanıldı. Lütfen yeni bir kod bekleyin"
|
||||
U2F:
|
||||
NotExisting: "U2F mevcut değil"
|
||||
Passwordless:
|
||||
@@ -768,6 +769,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Çok faktörlü OTP kontrolü başarılı"
|
||||
failed: "Çok faktörlü OTP kontrolü başarısız"
|
||||
reused: "Çok faktörlü OTP kodu yeniden kullanıldı"
|
||||
sms:
|
||||
added: "Çok faktörlü OTP SMS eklendi"
|
||||
removed: "Çok faktörlü OTP SMS kaldırıldı"
|
||||
|
||||
@@ -176,6 +176,7 @@ Errors:
|
||||
NotExisting: "Багатофакторний OTP (одноразовий пароль) не існує"
|
||||
NotReady: "Багатофакторний OTP (одноразовий пароль) не готовий"
|
||||
InvalidCode: "Недійсний код"
|
||||
Reused: "Цей код вже було використано. Будь ласка, зачекайте на новий код"
|
||||
U2F:
|
||||
NotExisting: "U2F не існує"
|
||||
Passwordless:
|
||||
@@ -762,6 +763,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "Перевірка багатофакторного OTP успішна"
|
||||
failed: "Перевірка багатофакторного OTP не вдалася"
|
||||
reused: "Код багатофакторного OTP використано повторно"
|
||||
sms:
|
||||
added: "Багатофакторний OTP SMS доданий"
|
||||
removed: "Багатофакторний OTP SMS видалений"
|
||||
|
||||
@@ -177,6 +177,7 @@ Errors:
|
||||
NotExisting: "OTP (一次性密码) 不存在"
|
||||
NotReady: "OTP (一次性密码) 还没准备好"
|
||||
InvalidCode: "无效的验证码"
|
||||
Reused: "此验证码已被使用。请等待新的验证码"
|
||||
U2F:
|
||||
NotExisting: "U2F 不存在"
|
||||
Passwordless:
|
||||
@@ -768,6 +769,7 @@ EventTypes:
|
||||
check:
|
||||
succeeded: "验证 MFA OTP 成功"
|
||||
failed: "验证 MFA OTP 失败"
|
||||
reused: "重复使用 MFA OTP 验证码"
|
||||
sms:
|
||||
added: "添加了多因素 OTP 短信"
|
||||
removed: "删除了多因素 OTP 短信"
|
||||
|
||||
Reference in New Issue
Block a user