HTTP basic authentication is a simple challenge and response mechanism with which a server can request authentication information (a user ID and password) from a client. The client passes the authentication information to the server in an Authorization header.
In various PHP projects that I've worked on, very often I have come across code that relies on using PHP's explode
function to generate an array from a string based on a delimiter.
This is also the case for how many devs choose to parse the Basic Authorization
header:
<?php
if (isset($_SERVER["HTTP_AUTHORIZATION"]) {
$auth = $_SERVER["HTTP_AUTHORIZATION"];
$auth_array = explode(" ", $auth);
$un_pw = explode(":", base64_decode($auth_array[1]));
$un = $un_pw[0];
$pw = $un_pw[1];
}
The code above might seem ok, and maybe with some additional user input validation it could work, but not in all cases.
Let's have a look at Symfony's approach to deal with this:
<?php
if (isset($_SERVER["HTTP_AUTHORIZATION"]) && 0 === stripos($_SERVER["HTTP_AUTHORIZATION"], 'basic ')) {
$exploded = explode(':', base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)), 2);
if (2 == \count($exploded)) {
list($un, $pw) = $exploded;
}
}
First of all, it checks if the header passed really starts with the string Basic
(case insensitive). Then, it uses explode
to split the decoded credentials, but it passes along a less known third parameter:
Using explode(':', 'username:pass:123', 2)
will generate an array
of 2 elements: username
and pass:123
. This prevents the possibility of obtaining a shorter password string if it contains a colon(':').
According to the 'RFC 7617' usernames with a colon can not be used in an Authorization header.
Here's the relevant portion from the RFC:
... Furthermore, a user-id containing a colon character is invalid, as the first colon in a user-pass string separates user-id and password from one another; text after the first colon is part of the password. User-ids containing colons cannot be encoded in user-pass strings.
On servers running Apache with the php-cgi handler, the server will not pass the HTTP Authorization header to PHP.
To avoid smashing your keyboard, just add this to your .htaccess
file:
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
The basic authorization header is only secure if your connection is done over HTTPS since otherwise the credentials are sent in encoded plain text (not encrypted) over the network which is a huge security issue.
To conclude, the various implementation flaws that basic authentication has can cause serious concerns. However, since it is already a part of many applications, the best thing we can do is to take all possible precautions.
Photo by Markus Voetter on Unsplash