Skip to content

Instantly share code, notes, and snippets.

@killua-eu
Last active January 22, 2016 23:56
Show Gist options
  • Save killua-eu/d45ac9a7c8073f24876b to your computer and use it in GitHub Desktop.
Save killua-eu/d45ac9a7c8073f24876b to your computer and use it in GitHub Desktop.
<?php
// for security concerns read:
// https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/
// http://www.slideshare.net/rjsmelo/php-lx-owasptop10
// https://packagist.org/packages/lcobucci/jwt
ini_set('track_errors', true);
ini_set('display_errors', true);
error_reporting(E_ALL);
require __DIR__ . '/vendor/autoload.php';
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\ValidationData;
use Lcobucci\JWT\Signer\Hmac\Sha256;
$_glued['jwt']['issuer'] = 'http://localhost';
$_glued['jwt']['key'] = 'secretkey';
$htm_open="<html>"
. " <head>"
. " <style>"
. " html,div,p {
font-family: Roboto Slab, Arial;
font-size: 9pt;
}"
. " </style>"
. " </head>"
. " <body>";
$htm_navi="<a href='index.php'>home</a> <a href='?a=login'>login</a> "
. "<a href='?a=logout'>logout</a> <a href='?a=secret'>secret</a>";
function prn($name,$content)
{
echo "<b>".$name."__</b>".$content."<br />";
}
function get_client_ip() {
$ipaddress = '';
if (getenv('HTTP_CLIENT_IP'))
$ipaddress = getenv('HTTP_CLIENT_IP');
else if(getenv('HTTP_X_FORWARDED_FOR'))
$ipaddress = getenv('HTTP_X_FORWARDED_FOR');
else if(getenv('HTTP_X_FORWARDED'))
$ipaddress = getenv('HTTP_X_FORWARDED');
else if(getenv('HTTP_FORWARDED_FOR'))
$ipaddress = getenv('HTTP_FORWARDED_FOR');
else if(getenv('HTTP_FORWARDED'))
$ipaddress = getenv('HTTP_FORWARDED');
else if(getenv('REMOTE_ADDR'))
$ipaddress = getenv('REMOTE_ADDR');
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
function fingerprint($float) {
$secret = "kjfslj3242";
return hash('ripemd160', get_client_ip().$float.$secret);
}
////////////////////////////////////////////////////////////////////////////////
// About JWT ///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// http://www.slideshare.net/ivanrosolen/json-web-tokens
// https://developer.atlassian.com/static/connect/docs/latest/concepts/understanding-jwt.html
// http://codereview.stackexchange.com/questions/111402/jwt-simple-api-example
// iss: The issuer of the token
// sub: The subject of the token
// aud: The audience of the token
// exp: Token expiration time defined in Unix time
// nbf: “Not before” time that identifies the time before which the JWT must not be accepted for processing
// iat: “Issued at” time, in Unix time, at which the token was issued
// jti: JWT ID claim provides a unique identifier for the JWT
$signer = new Sha256();
$builder = new Builder;
$uin = 123;
$jti = hash('sha256',$_glued['jwt']['key'].".".time().".".$uin.".".mt_rand());
$cookie_name = "jwt";
$token = $builder->setIssuer($_glued['jwt']['issuer']) // Configures the issuer (iss claim)
->setAudience(fingerprint($uin)) // Configures the audience (aud claim) - secret+uid+ip address
->setId($jti, true) // Configures the id (jti claim), replicating as a header item
->setIssuedAt(time()) // Configures the time that the token was issue (iat claim)
->setNotBefore(time() - 1) // Configures the time that the token can be used (nbf claim)
->setExpiration(time() + 120) // Configures the expiration time of the token (exp claim)
->set('uid', $uin) // Configures a new claim, called "uid"
->set('firstname', 'Pavel') // Configures a new claim, called "uid"
->sign($signer, $_glued['jwt']['key']) // creates a signature using "testing" as key
->getToken(); // Retrieves the generated token
if (isset($_GET['a']) && ($_GET['a']==="login")) {
////////////////////////////////////////////////////////////////////////////
// Login ///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
setcookie($cookie_name,$token, time() + 120, "/");
echo $htm_open
. "<h1>login</h1>" . $htm_navi
. "<br /><br /><b>Logging you in:</b><br /><br />";
prn("jti",$jti);
prn("token",$token);
} elseif (isset($_GET['a']) && ($_GET['a']==="logout")) {
////////////////////////////////////////////////////////////////////////////
// Logout //////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
setcookie ($cookie_name, "", time() - 3600, "/");
echo $htm_open
. "<h1>logout</h1>" . $htm_navi
. "<br /><br /><b>Logging you out (\$_COOKIE vardump):</b><br /><br />";
var_dump($_COOKIE);
} elseif (isset($_GET['a']) && ($_GET['a']==="secret")) {
////////////////////////////////////////////////////////////////////////////
// Private /////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
echo $htm_open
. "<h1>private</h1>" . $htm_navi
. "<br /><br /><b>Logging you out (\$_COOKIE vardump):</b><br /><br />";
if(!isset($_COOKIE[$cookie_name])) {
echo "Not logged in, jwt cookie ".$cookie_name." is not set!";
} else {
echo "Cookie found, lets look inside: <br />";
echo $_COOKIE[$cookie_name]."<br /><br />";
$token = $_COOKIE[$cookie_name];
$token = (new Parser())->parse((string) $token); // Parses from a string
$token->getHeaders(); // Retrieves the token headers
$token->getClaims(); // Retrieves the token claims
/*
WARN: before validating the content you would probably like to verify the token signature:
*/
prn("cookieuid",$token->getClaim('uid')); // will print "123"
prn("cookiejti",$token->getHeader('jti'));
prn("currjti",$jti);
prn("cookieiss",$token->getClaim('iss'));
/*
$uid = (string) $token->getClaim('uid');
if ( !$uid ) {
echo "Unable to find user";
}*/
$data = new ValidationData(); // It will use the current time to validate (iat, nbf and exp)
$data->setIssuer($_glued['jwt']['issuer']);
$data->setAudience(fingerprint("123")); // replace with ip fingerprint of the user of the jwt cookie
$jti = $token->getHeader('jti');
$data->setId($jti);
/*
if ( $token->validate($data) !== true ||
$token->verify($signer, $_glued['jwt']['key']) !== true ) {
echo "unauthorized";
} else {
echo "showing my boobies";
}
*/
// validating data according to the $data validation bag (checking issuer, aoudiene and b default exp and friends)
$data_valid = $token->validate($data);
echo "<br />..... data valid: ".$data_valid."<br />";
if ( $token->validate($data) === true ) {
echo "<br />";
if ( $token->verify($signer, $_glued['jwt']['key']) === true ) { // verifying signature
// TODO: blacklist jti here (its been used)
// TODO: add some ttl on blacklisted jtis. ttl > time to log out
// $jti = $token->getHeader('jti');
echo "Showing my php boobies";
} else {
echo "Signature not verified, tempered cookie/";
}
} else { echo "So, the signature is right, but your data wrong. Someone can guess your hashes, you're screwed"; }
}
// iss: The issuer of the token
// sub: The subject of the token
// aud: The audience of the token
// exp: Token expiration time defined in Unix time
// nbf: “Not before” time that identifies the time before which the JWT must not be accepted for processing
// iat: “Issued at” time, in Unix time, at which the token was issued
// jti: JWT ID claim provides a unique identifier for the JWT
} else {
////////////////////////////////////////////////////////////////////////////
// Index.php ///////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
echo $htm_open
. "<h1>main</h1>" . $htm_navi
. "<br /><br /><b>Creating a nice new token:</b><br /><br />";
prn("ip",get_client_ip());
prn("finger",fingerprint("123")); // use something more floating instead of 123
prn("jti",$jti);
prn("token",$token);
echo "<br /><br /><b>Parsing the nice new token:</b><br /><br />";
$token = (new Parser())->parse((string) $token); // Parses from a string
$hdr = $token->getHeaders(); // Retrieves the token headers
$clm = $token->getClaims(); // Retrieves the token claims
//var_dump($hdr);
//var_dump($clm);
prn("getuid",$token->getClaim('uid')); // will print "123"
prn("getjti",$token->getHeader('jti'));
prn("getiss",$token->getClaim('iss'));
prn("gettoken",$token);
echo "<br /><br /><b>Validating the nice new token:</b><br /><br />";
$data = new ValidationData(); // It will use the current time to validate (iat, nbf and exp)
$data->setIssuer($_glued['jwt']['issuer']);
$data->setAudience(fingerprint($uin));
$data->setId($jti);
var_dump($token->validate($data)); // true, because validation information is equals to data contained on the token
echo '<br />';
var_dump($token->verify($signer, 'wrong key')); // false, because the key is different
echo '<br />';
var_dump($token->verify($signer, $_glued['jwt']['key'])); // true, because the key is the same
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment