Search code examples
phpsymfonyauthenticationbasic-authentication

Authentication for HTTP Basic with a field different from password


On a Symfony 5 project, I have a User entity with both fields "password" (hashed) and "smsCode" (plain).

When creating an account, the smsCode is used for authentication at first, until the user later sets a password (and then we use the password when not empty and ignore the smsCode).

What I'm trying to achieve: Authentication through HTTP Basic, but using the smsCode instead of the hashed password.

I managed to make this work using the form login by editing the checkCredentials() function on my LoginFormAuthenticator: I can login through the form using my SMS code instead of my password.

But when I try to authenticate through HTTP Basic, the checkAuthentication() function on DaoAuthenticationProvider.php is called, and this class fetches the password using $user->getPassword(). Is there any way I can overwrite / extend this checkAuthentication() function, so that I can first check the plain smsCode ($user->getSmsCode()) instead of the hashed password ?

#security:
encoders:
    App\Entity\User:
        algorithm: auto

providers:
    # used to reload user from session & other features (e.g. switch_user)
    app_user_provider:
        entity:
            class: App\Entity\User
            property: email
firewalls:
    dev:
        # profiler (dev only)
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        anonymous: true
        lazy: true
        provider: app_user_provider
        http_basic: true
        guard:
            authenticators:
                - App\Security\LoginFormAuthenticator
        logout:
            path: app_logout

I tried to edit my getPassword() function to check the smsCode first :

public function getPassword(): string
{
    if (!empty($this->smsCode)) {
        return (string) $this->smsCode;
    } else {
        return (string) $this->password;
    }
}

Unfortunately, since the password is hashed, it keeps failing at authentication since it's looking for a hashed version of the smsCode (the function isPasswordValid() in DaoAuthenticationProvider.php)

(The authentication works perfectly when giving the password instead of SMS code by the way)


Solution

  • In order to keep the logic (and code) flow the same, you currently already have the hashed password as a target variable, so when you generate the SMS code you can add a hashed version of your SMS code to the database to be used as a drop in replacement for the hashed password value.

    Then when using HTTPAuth you can simply referenced this "hashedSMS" string instead of the hashed password string, for comparison.


    NOTE: For security; the SMScode should have sufficient entropy, so should be long enough - typically longer than 8 characters.

    Typically in the current ecosystem SMS codes are shorter and less complex than passwords and because their method of transfer (via mobile phone text message) is extremely insecure and wide open for evesdropping and interception, this leaves the code as the weak point in the application security.

    This method of authentication should only be relied upon as a last resort.

    • Also as a final side note; lots of websites use SMS codes as a "two-factor-authentication" method, despite this not being 2FA and despite this form of authentication being easily open to abuse and compromise.

      In fact most big web businesses with ask your mobile number simply as a thin veneer of "security" and really just to collect a phone number to connect with your account for their own tracking and marketing purposes, whilst claiming it's some form of "better security".