I'm architecting a basic SSO solution to pass a user between two sites.
Site A handles authentication against a user database and then generates links to Site B which pass a HMAC token comprising a nonce and the user's ID. The HMAC is hashed with a shared secret between the two sites.
The following shows the token generation in PHP.
$sso['nonce'] = hash('sha1', rand() );
$sso['sharedKey'] = 'someVerySecureString';
$sso['hmacKey'] = hash_hmac ( 'sha256', $test['sharedKey'] , $test['nonce'] );
$sso['userId'] = '123456';
$sso['hmac'] = hash_hmac ( 'sha256', $test['userId'] , $test['hmacKey'] );
$sso['url'] = '/?id=' . urlencode($test['userId']) . '&nonce=' . urlencode($test['nonce']) . '&hmac=' . urlencode($test['hmac']);
I'm using the nonce to HMAC the key before transmission.
This is the PHP function on Site B to validate the token:
function validateSSOToken($sharedKey='someVerySecureString') {
$isValid = false;
if ( isset( $_GET['id'] )
&& isset( $_GET['nonce'] )
&& isset( $_GET['hmac'] )
&& strlen( $_GET['nonce'] ) == 40
&& strlen( $_GET['hmac'] ) == 64) {
$userId = $_GET['id'];
$nonce = $_GET['nonce'];
$hmac = $_GET['hmac'];
// Sign the key with the nonce to get the tmp key
$hmacKey = hash_hmac ( 'sha256', $sharedKey, $nonce );
// rebuild the string to sign
$localHmac = hash_hmac ( 'sha256', $userId , $hmacKey );
// Compare against the incoming key
$isValid = $localHmac == $hmac ? true : false;
}
return $isValid;
}
I'm aware of the replay attack vector and will be addressing it in due course.
Could you advise if this is secure? Is there anything else I might look at considering to achieve the same goal?
isset()
check.isset( $_GET[ 'id' ], $_GET[ 'nonce' ], $_GET[ 'hmac' ] )
. \$\endgroup\$