I've set up a login system that works more or less like this:

1) The user enters the data

2) The data is hashed locally using SHA256 (To reduce the risk of someone stealing the password through a man in the middle attack and using it somewhere else).

3) The hashes are sent over a secure connection to the server

4) Once they arrive, they are immediately checked to make sure they don't contain invalid characters. This is the function:

function IsHexadecimal($pass){
    $allowedChars = '0123456789abcdef';
    $passLenght = strlen($pass);
    for($i = (int)0; $i < $passLenght; $i++){
        if(strpos($allowedChars, $pass[$i]) == false && $allowedChars[0] != $pass[$i]){
            return false;

    return true;

5) If they are valid hexadecimal characters, the authentication process goes on: the hashes are combined with a randomly generated 64-char salt assigned to that particular user, then hashed again using pbkdf2. Lastly, this new hash is compared against the one store in the database.

Since I'm following the default method to protect against SQL injection attacks - escaping the input - I wanted to ask if such an attack could be carried out against the system I've set up.

  • 2
    It might (?) be possible if you mess up your encodings somehow (e.g. database uses a different encoding to PHP), but you should definitely use parameterized queries regardless. – grc Jun 23 '16 at 10:49
  • The default method for protecting against SQLi is not escaping the input. It is using prepared statements. While this is probably fine (see @grc comment above), I asume you have more queries and chanses are at least one of them are vulnerable. – Anders Jun 23 '16 at 11:59

Firstly, I would recommend to use below function, that would be more efficient and stricter in my opinion.

    function IsHexadecimal($pass)
        return preg_match('/^[0-9a-f]{64}$/i', $pass);

    // or as @martinstoeckli suggested
    function IsHexadecimal($pass)
        return (ctype_xdigit($pass) && strlen($pass) === 64);

This function will return boolean (TRUE or FALSE) and it will match 0-9, uppercase and lowercase a-f (see /i flag) and checks for an exact length of 64 characters, which your function currently doesn't.

Also I'd suggest to rename the function IsHexadecimal to IsSHA256format in case you will use the length check as suggested in above two functions.

Secondly, I have personally never heard of any SQL injections that use hexadecimals only. I don't consider this technically possible.

Unless there is another function replacing some data and actually creating an SQL injection with a certain order of characters. This is only possible when $pass passed the IsHexadecimal function (so in 0-9a-fA-F{64} format) and the data is not properly sanitized in the SQL query, but that seems highly unlikely.

Also, I'd recommend to rehash the SHA256 hash server-side (like you described) but using stretching and especially salting techniques. This way, the hash that is send over TLS will be different than the one that is stored in the database and will be harder to guess when leaked since you used salting and stretching. A good article about this is Salted Password Hashing - Doing it Right. In your current situation the password is just hashed twice without a salt. The hash is still quite easy to compare against wordlist / rainbow table.

  • Or you could just use ctype_xdigit() ;.) – martinstoeckli Jun 23 '16 at 13:03
  • @martinstoeckli I added your suggestion ;) – Bob Ortiz Jun 23 '16 at 13:08
  • 1
    I am combining the hash received from the user with a salt, and hashing tham [See 5)]. If fact, I followed the exact article you've linked to. – AvidScifiReader Jun 23 '16 at 19:31

No, injection with just hexadecimal characters is not possible.

Another (better?) way to prevent SQL injection is to use prepared statements:

$stmt = $mysqli->prepare("SELECT * FROM User WHERE Password=?");
$stmt->bind_param("s", $password);

Because you leave it to the database engine to correctly put your data in the SQL query, SQL injection is not possible. This way you don't have to worry about whether you have escaped all your data correctly.

  • 1
    I would replace (better?) with (better!). :-) – Anders Jun 23 '16 at 11:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.