|
|
||
|---|---|---|
| .forgejo/workflows | ||
| example | ||
| src | ||
| tests | ||
| .gitignore | ||
| .php-cs-fixer.dist.php | ||
| CHANGES.md | ||
| composer.json | ||
| LICENSE | ||
| Makefile | ||
| phpstan.neon | ||
| phpunit.xml.dist | ||
| psalm.xml.dist | ||
| README.md | ||
Summary: Small OTP verification library
Description: PHP library to verify OTP codes and protect against replay and brute force attacks.
License: MIT
Introduction
PHP library to verify OTP codes and protect against replay and brute force attacks with support for PHP >= 8.2.
What
This is a library that includes TOTP verification and protection against replay and brute force attacks.
Why
High quality OTP verification libraries exist, e.g. christian-riesen/otp and spomky-labs/otphp which are popular and work well, however, they lack built-in support for protection against replay attacks and brute force attempts.
Features
- Supports PHP >= 8.2;
- Verifies TOTP codes;
- Protects againts replay attacks by storing the (used) OTP keys;
- Protects against brute force attacks by limiting the number of attempts in a certain time frame.
Database
A database is needed to store OTP secrets and used OTP keys. Currently only SQLite is tested, but others may work.
<?php
$storage = new fkooman\OTP\DBStorage(new PDO('sqlite:/path/to/db.sqlite'));
You can call init() on the Storage object to initialize the database, do
this only once, during application installation:
<?php
$storage->init();
API
Registration
A TOTP application, e.g. running on a mobile device will need to be configured with the TOTP secret and generate a valid OTP key before registration can succeed. Your application can for example generate a TOTP secret, generate a QR code and allow the user to import that in their OTP application.
Most (T)OTP applications can handle a QR code for enrollment, making it much easier for users to configure their application. This library can generate a Key-URI to make this easier with all the right parameters set:
<?php
$userId = 'foo';
$otpInfo = fkooman\OTP\OTPInfo::create();
$keyUri = KeyURI::generate($userId, 'My Service', $otpInfo);
This will return something like this:
otpauth://totp/My%20Service:foo?secret=RMO6LYUJPDMRZTCA5JKP4TOLRYKHBF2H&algorithm=SHA1&digits=6&period=30&issuer=My%2520Service
Use this URI in a QR code and show it to the user. Once you get back a valid OTP key from the user, e.g. entered in a form, you can complete the registration:
$otp = new OTP($storage);
$otpKey = '123456';
$otp->register($userId, $otpInfo, $otpKey);
Validation
$userId = 'foo';
$otpKey = '234567';
try {
$otp->validate($userId, $otpKey);
echo 'VALID';
} catch (fkooman\OTP\Exception\OTPException $e) {
echo 'ERROR: '.$e::class.PHP_EOL;
}
You can catch the specific OTP Exception for a particular case, e.g. you can catch:
| Exception | When? |
|---|---|
InvalidOTPException |
The user provided an invalid OTP code |
ReplayOTPException |
An OTP code was reused, i.e. "replayed" |
TooManyAttemptsOTPException |
Too many (invalid) attempts were made |
"Too many" in this case means, 10 invalid OTP codes in a row.
NOTE: you can not reuse the OTP key used for registration for verification afterwards. You have to wait for the next window, i.e. up to 30 seconds by default.
Inspiration
This library was inspired by other software, both in idea and sometimes code. A list:
- christian-riesen/otp (MIT) and spomky-labs/otphp (MIT), mostly for the ideas regarding accepting TOTP keys from the previous and next time window(s).
License
MIT.