Session Fingerprint Drift Review
Compares a stored session fingerprint with the current request fingerprint and returns an explicit drift decision.
Purpose
Compares a stored session fingerprint with the current request fingerprint and returns an explicit drift decision.
Snippet details
ContextSecurityLevelAdvancedCopy-and-paste statusMarked safe after review.Categories
- Security
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Session Fingerprint Drift Review.
*
* Purpose:
* Reviews whether stable request traits have changed enough to require a
* session challenge, rotation, or logout.
*
* @param array $session_state Session state containing the stored fingerprint.
* @param array $server_input $_SERVER-style request data.
* @return array Drift review decision and current fingerprint.
*/
function ogSnippetSessionFingerprintDriftReview(array $session_state, array $server_input): array {
$user_agent = '';
$accept_language = '';
$remote_address = '';
if (isset($server_input['HTTP_USER_AGENT']) === true) {
$user_agent = trim((string) $server_input['HTTP_USER_AGENT']);
}
if (isset($server_input['HTTP_ACCEPT_LANGUAGE']) === true) {
$accept_language = strtolower(substr(trim((string) $server_input['HTTP_ACCEPT_LANGUAGE']), 0, 32));
}
if (isset($server_input['REMOTE_ADDR']) === true) {
$remote_address = trim((string) $server_input['REMOTE_ADDR']);
}
$address_parts = explode('.', $remote_address);
$address_group = '';
if (count($address_parts) >= 2) {
$address_group = $address_parts[0].'.'.$address_parts[1];
}
$fingerprint_seed = $user_agent.'|'.$accept_language.'|'.$address_group;
$current_fingerprint = hash('sha256', $fingerprint_seed);
$stored_fingerprint = '';
if (isset($session_state['fingerprint']) === true) {
$stored_fingerprint = (string) $session_state['fingerprint'];
}
if ($stored_fingerprint === '') {
return array(
'status' => 'initialize',
'message' => 'No stored fingerprint exists for this session.',
'fingerprint' => $current_fingerprint
);
}
if (hash_equals($stored_fingerprint, $current_fingerprint) === true) {
return array(
'status' => 'stable',
'message' => 'Session fingerprint has not drifted.',
'fingerprint' => $current_fingerprint
);
}
return array(
'status' => 'drifted',
'message' => 'Session fingerprint changed and should be challenged or rotated.',
'fingerprint' => $current_fingerprint
);
}
$expanse_server = array(
'HTTP_USER_AGENT' => 'Rocinante Console',
'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.9',
'REMOTE_ADDR' => '192.168.55.14'
);
$initial_review = ogSnippetSessionFingerprintDriftReview(array(), $expanse_server);
$second_review = ogSnippetSessionFingerprintDriftReview(array('fingerprint' => $initial_review['fingerprint']), $expanse_server);
echo 'Expanse session review: '.$second_review['status'];