fix: prevent TOTP passcode reuse within validity window
Store used TOTP passcodes in the keyvalue store after successful validation. On subsequent validation attempts, check if the passcode was already used for the same user and reject it with ErrTOTPPasscodeUsed. This prevents replay attacks where an intercepted TOTP code could be reused within its 30-second validity window.
This commit is contained in:
parent
5591ca94ba
commit
5f06e1dce5
|
|
@ -17,7 +17,9 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"strconv"
|
||||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
|
|
@ -136,6 +138,22 @@ func ValidateTOTPPasscode(s *xorm.Session, passcode *TOTPPasscode) (t *TOTP, err
|
|||
return nil, ErrInvalidTOTPPasscode{Passcode: passcode.Passcode}
|
||||
}
|
||||
|
||||
// Prevent passcode reuse: check if this passcode was already used
|
||||
usedKey := fmt.Sprintf("totp_used_%s_%s", strconv.FormatInt(passcode.User.ID, 10), passcode.Passcode)
|
||||
_, exists, err := keyvalue.Get(usedKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if exists {
|
||||
return nil, ErrTOTPPasscodeUsed{}
|
||||
}
|
||||
|
||||
// Mark this passcode as used
|
||||
err = keyvalue.Put(usedKey, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func TestTOTPPasscodeCannotBeReused(t *testing.T) {
|
|||
defer s.Close()
|
||||
|
||||
// Generate a valid TOTP passcode for user1's secret from the fixture
|
||||
secret := "JBSWY3DPEHPK3PXP"
|
||||
secret := "JBSWY3DPEHPK3PXP" //nolint:gosec
|
||||
passcode, err := totp.GenerateCode(secret, time.Now())
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue