Laragear / WebAuthn

Authenticate users with Passkeys: fingerprints, patterns and biometric data.
MIT License
308 stars 37 forks source link

[1.x] Too long id (of Nitrokey) cause MySQL error #38

Closed Bubka closed 1 year ago

Bubka commented 1 year ago

PHP & Platform

8.1.11 - Windows 10

Database

MySQL 8.0.30

Laravel version

9.36.3

Have you done this?

Expectation

When registering a security key, the attestation is stored to db.

Description

When registering a Nitrokey, an error occurs when attestation is written to MySQL db because of a too long index (298 chars!)

This Nitrokey does not validate the assumption made here: https://github.com/DarkGhostHunter/Larapass/issues/14#issuecomment-665327620

Reproduction

// Using the WebAuthn repository tests.
// Change the CREDENTIAL_ID to a 255+ long string
// Then run the Tests\Http\Requests\AttestedRequestTest tests

class FakeAuthenticator
{
    public const CREDENTIAL_ID = 'owBYu_waGLhAOCg4EFzi6Lr55x51G2dR5yhJi8q2C3tgZQQL2aEi-nK3I54J6ILj70pJzR_6QxvA5XER17d7NA9EFe2QH3VoJYQGpO8G5yDoFQvsdkxNhioyMyhyQHNrAgTMGyfigIMCfhjk9te7LNYl9K5GbWRc4TGeQl1vROjBtTNm3GdpEOqp9RijWd-ShQZ95eHoc8SA_-8vzCyfmy-wI_K4ZqlQNNl85Fzg2GIBcC2zvcJhLYy1A2kw6JoBTAmz1ZCCgkTKWhzUvAJQpMpu40M67FqE0WkGZfSJ9A';    
    public const CREDENTIAL_ID_RAW = 'owBYu/waGLhAOCg4EFzi6Lr55x51G2dR5yhJi8q2C3tgZQQL2aEi+nK3I54J6ILj70pJzR/6QxvA5XER17d7NA9EFe2QH3VoJYQGpO8G5yDoFQvsdkxNhioyMyhyQHNrAgTMGyfigIMCfhjk9te7LNYl9K5GbWRc4TGeQl1vROjBtTNm3GdpEOqp9RijWd+ShQZ95eHoc8SA/+8vzCyfmy+wI/K4ZqlQNNl85Fzg2GIBcC2zvcJhLYy1A2kw6JoBTAmz1ZCCgkTKWhzUvAJQpMpu40M67FqE0WkGZfSJ9A=';

// ...
}

Stack trace & logs

// Error in VS Code during the execution of Tests\Http\Requests\AttestedRequestTest tests

node:events:504
      throw er; // Unhandled 'error' event
      ^

Error: ENOENT: no such file or directory, open 'd:\ SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'id' at row 1 in ...\WebAuthn\vendor\laravel\framework\src\Illuminate\Database\Connection.php'
Emitted 'error' event on Interface instance at:
    at ReadStream.onerror (node:readline:265:10)
    at ReadStream.emit (node:events:526:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: "d:\\ SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'id' at row 1 in ...\\WebAuthn\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php"
}

// In production stacktrace (from https://github.com/Bubka/2FAuth/issues/166#issuecomment-1460991223)
[2023-03-01 12:24:10] local.ERROR: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'id' at row 1 (SQL: insert into `web_authn_credentials` (`id`, `user_handle`, `type`, `transports`, `attestation_type`, `trust_path`, `aaguid`, `public_key`, `counter`, `user_id`, `updated_at`, `created_at`) values (owBYu_waGLhAOCg4EFzi6Lr55x51G2bhCQIYNOXkC3tgZQQL2aEi-nK3I54J6ILj70pJzR_6QxvA5XER17d7NA9EFe2QH3VoJYQGpO8G5yDoFQvsdkxNhioyMyhyQHNrAgTMGyfigIMCfhjk9te7LNYl9K5GbWRc4TGeQl1vROjBtTNm3GdpEOqp9RijWd-ShQZ95eHoc8SA_-8vzCyfmy-wI_K4ZqlQNNl85Fzg2GIBcC2zvcJhLYy1A2kw6JoBTAmz1ZCCgkTKWhzUvAJQpMpu40M67FqE0WkGZfSJ9A, c6d01c4c-95fb-4e39-ab4f-78be47568837, public-key, [], none, {"type":"Webauthn\\TrustPath\\EmptyTrustPath"}, 00000000-0000-0000-0000-000000000000, XXXXXXXXXXXXXXXXX, 25, 1, 2023-03-01 12:24:10, 2023-03-01 12:24:10)) {"userId":1,"exception":"[object] (Illuminate\\Database\\QueryException(code: 22001): SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'id' at row 1 (SQL: insert into `web_authn_credentials` (`id`, `user_handle`, `type`, `transports`, `attestation_type`, `trust_path`, `aaguid`, `public_key`, `counter`, `user_id`, `updated_at`, `created_at`) values (owBYu_waGLhAOCg4EFzi6Lr55x51G2bhCQIYNOXkC3tgZQQL2aEi-nK3I54J6ILj70pJzR_6QxvA5XER17d7NA9EFe2QH3VoJYQGpO8G5yDoFQvsdkxNhioyMyhyQHNrAgTMGyfigIMCfhjk9te7LNYl9K5GbWRc4TGeQl1vROjBtTNm3GdpEOqp9RijWd-ShQZ95eHoc8SA_-8vzCyfmy-wI_K4ZqlQNNl85Fzg2GIBcC2zvcJhLYy1A2kw6JoBTAmz1ZCCgkTKWhzUvAJQpMpu40M67FqE0WkGZfSJ9A, c6d01c4c-95fb-4e39-ab4f-78be47568837, public-key, [], none, {\"type\":\"Webauthn\\\\TrustPath\\\\EmptyTrustPath\"}, 00000000-0000-0000-0000-000000000000, XXXXXXXXXXXXXXXXXXXX, 25, 1, 2023-03-01 12:24:10, 2023-03-01 12:24:10)) at /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Connection.php:712)
[stacktrace]
#0 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Connection.php(672): Illuminate\\Database\\Connection->runQueryCallback()
#1 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Connection.php(502): Illuminate\\Database\\Connection->run()
#2 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Connection.php(454): Illuminate\\Database\\Connection->statement()
#3 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2980): Illuminate\\Database\\Connection->insert()
#4 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(1657): Illuminate\\Database\\Query\\Builder->insert()
#5 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1164): Illuminate\\Database\\Eloquent\\Builder->__call()
#6 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(994): Illuminate\\Database\\Eloquent\\Model->performInsert()
#7 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php(267): Illuminate\\Database\\Eloquent\\Model->save()
#8 /var/www/2fauth/vendor/darkghosthunter/larapass/src/WebAuthnAuthentication.php(93): Illuminate\\Database\\Eloquent\\Relations\\HasOneOrMany->save()
#9 /var/www/2fauth/vendor/darkghosthunter/larapass/src/Http/RegistersWebAuthn.php(47): App\\Models\\User->addCredential()
#10 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\\Http\\Controllers\\Auth\\WebAuthnRegisterController->register()
#11 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\\Routing\\Controller->callAction()
#12 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Route.php(262): Illuminate\\Routing\\ControllerDispatcher->dispatch()
#13 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\\Routing\\Route->runController()
#14 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Router.php(721): Illuminate\\Routing\\Route->run()
#15 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
#16 /var/www/2fauth/app/Http/Middleware/RejectIfReverseProxy.php(26): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#17 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\RejectIfReverseProxy->handle()
#18 /var/www/2fauth/app/Http/Middleware/KickOutInactiveUser.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#19 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\KickOutInactiveUser->handle()
#20 /var/www/2fauth/app/Http/Middleware/LogUserLastSeen.php(35): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#21 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\LogUserLastSeen->handle()
#22 /var/www/2fauth/vendor/laravel/passport/src/Http/Middleware/CreateFreshApiToken.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#23 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\\Passport\\Http\\Middleware\\CreateFreshApiToken->handle()
#24 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#25 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle()
#26 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(44): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#27 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Auth\\Middleware\\Authenticate->handle()
#28 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#29 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle()
#30 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#31 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest()
#32 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Session\\Middleware\\StartSession->handle()
#33 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#34 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle()
#35 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#36 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle()
#37 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#38 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Router.php(723): Illuminate\\Pipeline\\Pipeline->then()
#39 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Router.php(698): Illuminate\\Routing\\Router->runRouteWithinStack()
#40 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Router.php(662): Illuminate\\Routing\\Router->runRoute()
#41 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Routing/Router.php(651): Illuminate\\Routing\\Router->dispatchToRoute()
#42 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(167): Illuminate\\Routing\\Router->dispatch()
#43 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
#44 /var/www/2fauth/app/Http/Middleware/ForceJsonResponse.php(20): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#45 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\ForceJsonResponse->handle()
#46 /var/www/2fauth/app/Http/Middleware/SetLanguage.php(54): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#47 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\SetLanguage->handle()
#48 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#49 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#50 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
#51 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#52 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#53 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
#54 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#55 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
#56 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#57 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
#58 /var/www/2fauth/vendor/fruitcake/laravel-cors/src/HandleCors.php(38): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#59 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fruitcake\\Cors\\HandleCors->handle()
#60 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#61 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Http\\Middleware\\TrustProxies->handle()
#62 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#63 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(142): Illuminate\\Pipeline\\Pipeline->then()
#64 /var/www/2fauth/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(111): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
#65 /var/www/2fauth/public/index.php(73): Illuminate\\Foundation\\Http\\Kernel->handle()
#66 {main}
DarkGhostHunter commented 1 year ago

Merci!

The Nitrokey, or any other key, might use lengthier keys. For that, the current workaround is to edit the column migration to allow for larger keys. This should work if you're on production:

ALTER TABLE webauthn_credentials MODIFY COLUMN id VARCHAR(512);

AFAIK, there is no "id length" standard. In any case, I'll push a patch to make push the string limitation further to 510 characters.