【问题标题】:Validate curl CURLOPT_HTTPHEADER request on server side在服务器端验证 curl CURLOPT_HTTPHEADER 请求
【发布时间】:2018-11-19 15:05:19
【问题描述】:

我开发了一个小型网络服务,它将接受用户查询并将数据作为 json 响应返回。一切正常。但我想知道如何设置和比较 来自客户端的授权令牌作为 curl 标头的一部分。这是我发送请求的代码。我仍然没有在 FetchData.php 上设置任何验证。我想在 FetchData.php 上实现它。如何实现?

$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);
}

在上面的代码中,我添加了这个授权令牌。但实际上这不是在服务器端设置的,我的意思是fetchData.php

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

所以我的问题是如何在fetchData.php 中设置此授权令牌并验证来自客户端的令牌?任何帮助将不胜感激。

【问题讨论】:

  • 如果令牌无效,我确定 fetchData.php 会返回错误。除非您可以访问与远程 Web 服务相同的身份验证/授权代码,否则很难看出您希望如何提前验证它。 (如果您确实 有权访问它,那么这意味着 Web 服务的身份验证过程受到严重损害)。附:客户端如何获取令牌以便将其传递给您的 PHP 代码?从您的问题来看,这部分有点不清楚。
  • @ADyson,这就是我要问的,我没有在 FetchData.php 上设置任何内容。如何在 FetchData.php 上设置?
  • “但实际上这并没有在服务器端设置” - 更准确地说,你甚至没有寻找它 …?因此,通过了解如何在 PHP 中读取请求标头来开始您的研究。
  • 好吧,这样做的安全性质量很差,但正如 misorude 所说,如果您现在只想这样做,您可以轻松研究如何读取标头值。您可能需要考虑该服务在未来将如何发展,您是否需要拥有多个用户身份,他们的会话是否应该过期等。查看诸如 OAuth2 之类的方案。然后找到一个可以插入 API 的现有实现 - 创建自己的安全性通常不是一个好主意,你最终只会重复其他人已经克服的错误。
  • "如何阅读 curl CURLOPT_HTTPHEADER"...嗯,是的,这没有任何意义,因为当它到达服务器时,它只是一个 HTTP 请求。它是用 curl 创建的这一事实是无关紧要的,服务器对此一无所知。不过,这就是 HTTP 的优点——客户端或服务器是谁或什么并不重要,只要它们都使用相同的协议即可。很高兴你修好了。

标签: php rest curl http-head


【解决方案1】:

如果只有 1 个令牌,您可以硬编码,

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

}else{
    // wrong token
}

但是,如果您有多个标记,则应将它们预先散列保存在数据库中,这是一个带有标记“foo”、“bar”和“baz”的 SQLite 示例:

$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)));
}

您可以通过运行检查令牌是否有效

$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 =(
}

现在你可能想知道

为什么要对令牌进行哈希处理,为什么不以明文形式保存它们?
这是关于防止定时攻击,哈希会进行长度填充,因此黑客无法使用定时攻击来推断令牌的实际长度(这可以帮助攻击者进行暴力/字典攻击),并且实际令牌、输入字符串和定时攻击的正确位数之间没有相关性,即使黑客设法推断出the first 8 bits of the hash is definitely 10010111,对于推断的每个位,找到一个哈希到 known-bits+1 的字符串变得越来越困难,最终结果是用定时攻击来攻击这个方案应该是完全不可行的(至少使用 sha2- 384)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-13
    • 1970-01-01
    • 2014-02-22
    • 2015-09-23
    • 2017-11-30
    • 2012-04-04
    • 2012-11-17
    • 1970-01-01
    相关资源
    最近更新 更多