Sample Header Ad - 728x90

Indexing of hash-value column vs INT IDs for session tokens

0 votes
1 answer
161 views
Let's say: - your application should use session IDs generated with a CSPRNG, which shall authenticate your user sessions - your system uses PHP 8.2 and MariaDB 10.6 Which of the approaches below performs better: Approach A (Index on hashed session ID): - the PK column of your sessions table is the one which holds the output of PHP's password_hash function, applied to a value generated via a CSPRNG. - upon every incoming request, you hash the session ID delivered by the client, and query the DB by that hash. Approach B (Index on decrypted INT session ID): - the PK column of your sessions table is a simple integer, which is encrypted before being delivered to your client. - upon every incoming request, you decrypt the session ID delivered by the client. - if the decryption fails, someone tampered with the token --> return 401 - if the decryption succeeds, you query by the accordingly obtained session ID. Is the performance hit you get from indexing hashes vs INTs negligible in such a case? I personally also like the fact that approach B provides a way to verify if someone tampered with the token, and avoids the DB-roundtrip if so. Do you see an approach to do so using hashes, as in approach A? **UPDATE** So let's say you have the following table:
CREATE TABLE sessdata (
  sid_hash BINARY(60) NOT NULL PRIMARY KEY,
  sdata JSON NOT NULL
);
With this, the simple insertion and subsequent attempted retrieval via hash using PHP and PDO fails:
$pdo = new PDO(
    dsn     : "mysql:host=localhost;dbname=$db_name;charset=utf8mb4",
    username: $db_user,
    password: $db_p,
    options : [
                  // Throw PDO Exception in case of any error
                  PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                  // Fetch the obtained result as associative array by default
                  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
              ]
);

$raw_binary_sid = random_bytes(32);

$hash = password_hash(
    password: $raw_binary_sid,
    algo    : PASSWORD_DEFAULT
);

// Keep this somewhere in your storage
$base64_urlsafe_nopadding = sodium_bin2base64(
    string: $raw_binary_sid,
    id    : SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
);

$stmt = $pdo->prepare("INSERT INTO sessdata (sid_hash,sdata) VALUES (:hash,JSON_ARRAY())");

$stmt->execute(
    [
        'hash' => $hash
    ]
);

// Then in a separate PHP Session try to retrieve it, doesnt work 

$hash = password_hash(
    password: sodium_base642bin(
                  $base64_urlsafe_nopadding,
                  SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
              ),
    algo    : PASSWORD_DEFAULT
);

$stmt = $pdo->prepare("SELECT * FROM sessdata WHERE sid_hash = :hash");

$stmt->execute(
    [
        'hash' => $hash
    ]
);

$stmt->fetchAll(); // empty array = no records found
What am I missing here? **UPDATE 2** Okay got the problem. PDO by default binds parameter to a query using the PDO::PARAM_STR data type / string data type. If I bind the parameter as PDO::PARAM_LOB data type instead during the insert and select operations, it all works. So in the end there are two final questions: 1. Is it correct that queries using the above-mentioned code will perform much faster than if I would index the hash column with the VARCHAR(60) data type? 2. Are truncated inserts impossible; e.g. will the 60-character long strings generated in PHP via password_hash('password',PASSWORD_BCRYPT) always match exactly the length specified via BINARY(60) ? Or is it wiser to use VARBINARY(60) to avoid danger of eventually padded / truncated values?
Asked by DevelJoe (163 rep)
Jun 4, 2023, 08:33 PM
Last activity: Jun 6, 2023, 10:52 PM