Last active
January 22, 2016 23:56
-
-
Save killua-eu/d45ac9a7c8073f24876b to your computer and use it in GitHub Desktop.
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 | |
// 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