Insecure authentication method - Basic - PHP

Insecure authentication method - Basic - PHP

Need

Implementation of a secure authentication method

Context

  • Requirement of PHP 7.0 or later for running the application
  • Usage of Laravel framework for PHP web development

Description

Non compliant code

        Route::get('/user', function () {
    if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
        $username = $_SERVER['PHP_AUTH_USER'];
        $password = $_SERVER['PHP_AUTH_PW'];
        if ($username == 'admin' && $password == 'password') {
            return response()->json(['message' => 'Authenticated']);
        }
    }
    return response()->json(['message' => 'Unauthenticated'], 401);
});
        
        

In the code above, the server is using PHP's built-in $_SERVER['PHP_AUTH_USER'] and $_SERVER['PHP_AUTH_PW'] superglobals to perform Basic authentication. When a client sends a request to the '/user' endpoint, the server checks if the 'PHP_AUTH_USER' and 'PHP_AUTH_PW' headers are set. If they are set, it then compares the provided username and password to a hardcoded 'admin' and 'password' respectively.

The vulnerability lies in the fact that this authentication is performed over an insecure channel. This means that the credentials (username and password) are sent over the network in plaintext. An attacker who is able to intercept the network traffic could easily read these credentials and use them to impersonate the user.

Furthermore, the use of hardcoded credentials ('admin' and 'password') is a bad practice as it makes the server susceptible to brute force or dictionary attacks.

In addition, the server does not implement any form of session management. This means that the client has to send the credentials with every request, increasing the chances of them being intercepted.

Lastly, the server responds with a '401 Unauthenticated' status code and a JSON message if the authentication fails. This could potentially give an attacker information about the server's authentication mechanism.

Steps

  • Switch from Basic Authentication to a more secure method such as Token-based or OAuth2 authentication.
  • Ensure all data is sent over a secure channel. Use HTTPS instead of HTTP to encrypt all data in transit and prevent it from being intercepted.
  • Do not hardcode credentials in the code. Use environment variables or a secure configuration file to store sensitive information.
  • Implement a password hashing mechanism. Store and compare hashed passwords instead of plain text passwords.
  • Add a rate limiting mechanism to prevent brute force attacks.

Compliant code

        use Illuminate\\Http\\Request;
use Illuminate\\Support\\Facades\\Hash;
use Illuminate\\Support\\Facades\\Auth;

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

Route::post('/login', function (Request $request) {
    $credentials = $request->only('email', 'password');

    if (Auth::attempt($credentials)) {
        $token = $request->user()->createToken('MyApp')->plainTextToken;
        return response()->json(['token' => $token]);
    } else {
        return response()->json(['message' => 'Unauthenticated'], 401);
    }
});
        
        

The above code fixes the insecure authentication method vulnerability by implementing token-based authentication using Laravel's built-in auth:api middleware.

The /user route is now protected by the auth:api middleware, which requires a valid API token to access. The /login route is used to authenticate users and generate a new API token.

The Auth::attempt method is used to validate the user's credentials. If the credentials are valid, a new API token is generated using the createToken method and returned in the response. If the credentials are invalid, a 401 Unauthenticated response is returned.

This code assumes that you have set up Laravel's built-in token authentication and have a User model that uses the HasApiTokens trait.

Remember to always use HTTPS to ensure that all data, including the API token, is encrypted in transit. Also, do not hardcode credentials in the code. Use environment variables or a secure configuration file to store sensitive information.

Implement a password hashing mechanism. Laravel's Auth::attempt method automatically hashes the password and compares it to the hashed password stored in the database.

Add a rate limiting mechanism to prevent brute force attacks. Laravel provides built-in rate limiting middleware that you can use to limit the number of login attempts.

References