Created
March 8, 2010 22:03
-
-
Save nevali/325815 to your computer and use it in GitHub Desktop.
User Agent/Referrer Verification
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* Client sample implementing User Agent/Referrer Verification */ | |
/* Generate $key based on the contents of this resource */ | |
$referrer = 'http://example.com/page'; | |
/* This is our User-Agent string. The server must be expecting requests from this User-Agent. */ | |
$ua = 'My User Agent/1.0'; | |
/* Note that the client must have access to $referrer in order to generate the sha256-hmac */ | |
$key = hash_hmac_file('sha256', $referrer, $ua); | |
$ch = curl_init('http://example.com/some-resource'); | |
/* Send $key and the referrer URL along with our request; the server | |
* will check and verify each. If we don't have access to http://example.com/page to generate | |
* the proper key, our value of $key will be invalid and the request will fail. | |
* We don't actually send the User Agent itself. | |
*/ | |
curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-Verification-Key: ' . $key)); | |
curl_setopt($ch, CURLOPT_REFERER, $referrer); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($ch, CURLOPT_HEADER, true); | |
$resource = curl_exec($ch); | |
echo $resource; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* Server utility: cache a list of valid User Agent/Referrer Verification keys */ | |
/* Build the $keys array, exactly as in server.php */ | |
require_once('server-keys.php'); | |
/* Store the contents of $keys in a file. This file is read by server.php if it's present, | |
* rather than re-generating the list of keys on every request. | |
* | |
* Note! Ensure the web server forbids access to this file to clients, but that the user the | |
* web server runs as can read it. The simplest way to do this is to alter the path to put it | |
* outside of the DocumentRoot (or whatever your server's equivalent is), but still ensure it's | |
* world-readable. | |
*/ | |
if(!($f = fopen('key-cache.json', 'w'))) | |
{ | |
echo "fatal: failed to open key-cache.json for writing\n"; | |
exit(1); | |
} | |
fwrite($f, json_encode($keys)); | |
fclose($f); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* Server include: generate a list of valid User Agent/Referrer Verification keys */ | |
/* Valid user agents */ | |
$validUAs = array('My User Agent/1.0', 'Genuine Media Player 0.0.1'); | |
/* Names of files which exist on the server and will be considered valid referrers */ | |
$validReferrers = array('page' => 'http://example.com/page'); | |
$keys = array(); | |
/* $keys is an associative array, where the array key is the sha256-hmac of the content of the | |
* referring file and the HMAC key is the User-Agent string we expect the client to send. | |
* Thus, for each combination of the valid user agents and referrers, generate an HMAC. | |
* Each array value is itself an array made up of the actual referring URL and user-agent itself. | |
* | |
* The client can only generate the same key if its User-Agent matches one of the ones in | |
* $validUAs, and it has access to the same referring file. If for some reason it can't access | |
* it (for example, it requires a user name and password the client doesn't have), it won't | |
* be able to generate the correct key. | |
*/ | |
foreach($validReferrers as $ref => $refURL) | |
{ | |
foreach($validUAs as $ua) | |
{ | |
$keys[hash_hmac_file('sha256', $ref, $ua)] = array($refURL, $ua); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* Server sample implementing User Agent/Referrer Verification */ | |
if(file_exists('key-cache.json')) | |
{ | |
/* A key cache exists; just load and use it */ | |
$keys = json_decode(file_get_contents('key-cache.json')); | |
} | |
else | |
{ | |
/* Build a $keys array from scratch */ | |
require_once('server-keys.php'); | |
} | |
/* This will vary by SAPI; we don't really want to require a POST, nor do we want the key | |
* showing up in proxy logs, so we do it with a custom header. | |
*/ | |
$headers = apache_request_headers(); | |
$valid = false; | |
/* Check that the verification key, “referer” and user-agent headers are all present */ | |
if(isset($headers['X-Verification-Key']) && isset($headers['Referer'])) | |
{ | |
/* Look the verification key up in our list; check, just to make sure, that the | |
* referrer and sent by the client matches the one which generated the key. | |
* This extra check doesn’t really achieve much, as the client can set the Referer | |
* to anything it likes, but being strict never hurt anybody. | |
*/ | |
if(isset($keys[headers['X-Verification-Key']]) && $keys[headers['X-Verification-Key']][0] == $headers['Referer']) | |
{ | |
/* Everything matches up, allow the resource to be served to the client */ | |
$valid = true; | |
} | |
} | |
if(!$valid) | |
{ | |
header('HTTP/1.0 403 Forbidden'); | |
echo "Forbidden.\n"; | |
exit(); | |
} | |
echo "Success. This is the protected resource.\n"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment