2

I have developed a small webservice which will take user query and returns data as json response. Everything working fine. But I was wondering how to set and compare Authorization token from the client side as part of the curl header. This is my code to send request . Still I didn't set any validation thing on FetchData.php. I want to implement that on FetchData.php. How to implement that ?

$query = "select * from product_details where id = 2";
$query_params = array("query" => $query); 
$url = "http://localhost/api/fetchData.php?" . http_build_query($query_params, '', "&");
$curl = curl_init();
$token = 'ABCD123456';
$header[] = 'Authorization: Token '.$token;
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url,
CURLOPT_HTTPGET=>1,
CURLOPT_FAILONERROR=> 1,
CURLOPT_RETURNTRANSFER=> true,
CURLOPT_HTTPHEADER=>$header
));

$resp = curl_exec($curl);
if($resp === false)  
{
    $responseJson = new stdClass(); 
    $responseJson->status =  "FAILED";
    $responseJson->message = 'Send error: ' . curl_error($curl);
    throw new Exception(curl_error($curl)); 
}
else{
    $resp = curl_exec($curl);
}

In the above code I have added this authorization token . But acutually this was not set on server side I mean in fetchData.php.

$token = 'ABCD123456';
$header[] = 'Authorization: Token '.$token;

so my question is how to set up this authorization token thing in fetchData.php and validate the token which was from client side? Any help would be greatly appreciated.

user3408779
  • 981
  • 2
  • 19
  • 43
  • I'm sure fetchData.php will return an error if the token is invalid. Unless you have access to the same authentication/authorisation code as the remote webservice it's hard to see how you would expect to validate it in advance. (And if you _did_ have access to that, then it implies that the webservice's auth process is severely compromised). P.S. How is the client getting hold of the token in order to pass it to your PHP code? That part is somewhat unclear from your question. – ADyson Nov 19 '18 at 15:11
  • @ADyson, this is what I am asking, I didn't set anything on FetchData.php. How to set that on FetchData.php? – user3408779 Nov 19 '18 at 15:14
  • Ah so you're asking how to implement an authentication and authorisation system on the server-side? That's rather a large topic. You could buy a whole book on it. At the simplest level you could check whether the incoming request contains that value in the HTTP header, but of course just checking for a single static value every time is not very secure in the long term. – ADyson Nov 19 '18 at 15:17
  • yes, how to set that ? – user3408779 Nov 19 '18 at 15:18
  • 1
    _“But acutually this was not set on server side”_ - would be more precise to phrase that as, you didn’t even _look_ for it …? So start your research by finding out how to read request headers in PHP. – misorude Nov 19 '18 at 15:18
  • 1
    well it's very poor quality security just to do that, but as misorude says you can easily research how to read a header value, if that's all you want to do right now. You might want to consider how this service will evolve in the future, whether you need to have multiple user identities,whether their sessions should expire etc. Look into schemes such as OAuth2. And then find an existing implementation you can plug into your API - create your own security is usually not a good idea, you just end up repeating the mistakes that others have overcome already. – ADyson Nov 19 '18 at 15:21
  • Thank you , I just found getallheaders() this one. I was searching previously also like how to read curl CURLOPT_HTTPHEADER. But not able to find proper answer for my requrirement. Now this search query got my required result. "php read request headers" Thanks once again misorude and Adyson. – user3408779 Nov 19 '18 at 15:26
  • 1
    "how to read curl CURLOPT_HTTPHEADER"...ah ok yeah that makes no sense because when it gets to the server it's just a HTTP request. The fact it was created with curl is irrelevant, and the server has no knowledge of that. That's the nice thing about HTTP though - it doesn't matter who or what the client or server is, as long as they both speak the same protocol. Glad you fixed it. – ADyson Nov 19 '18 at 16:27

1 Answers1

2

if there is only 1 token, you can just hardcode it,

if(hash_equals(hash('sha384',$_SERVER['HTTP_AUTHORIZATION'],true),hash('sha384','the-real-token',true)){
    // correct token!

}else{
    // wrong token
}

however, if you have multiple tokens, you should save them pre-hashed in a DB, here's an SQLite example with the tokens "foo", "bar", and "baz":

$db = new PDO('sqlite::memory:', '', '', array(
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));
$db->exec('
CREATE TABLE tokens(id INTEGER PRIMARY KEY AUTOINCREMENT,
token TEXT,
hash BLOB);');
$stm=$db->prepare("INSERT INTO TOKENS(`token`,`hash`) VALUES(:token,:hash);");

$tokens=["foo","bar","baz"];
foreach($tokens as $token){
    $stm->execute(array(':token'=>$token,':hash'=>hash('sha384',$token,true)));
}

with this you can check if a token is valid by running

$stm=$db->prepare("SELECT EXISTS(SELECT 1 FROM hashes WHERE hash=?);");
$stm->execute([hash('sha384',$_SERVER['HTTP_AUTHORIZATION'],true]);
if($stm->fetch(PDO::FETCH_NUM)[0]==="1"){
    // valid token!
}else{
    // invalid token =(
}

now you might wonder

why bother hashing the tokens at all, why not just save them in plaintext?
it's about protecting against timing attacks, the hashes does length padding, so hackers cannot use timing attacks to infer the actual length of the tokens (which could help attackers a lot in performing a bruteforce/dictionary attack), and there is no correlation between the actual token, the input string, and the number of correct bits for a timing attack, and even if the hackers manage to infer that the first 8 bits of the hash is definitely 10010111, it gets progressively more difficult to find a string that hashes to known-bits+1 for each bit that gets inferred, with the end result being that attacking this scheme with timing attacks should be completely infeasible (at least with sha2-384)
hanshenrik
  • 19,904
  • 4
  • 43
  • 89