通过将用户的 ID + 时间加密为 JSON 创建访问令牌

Creating access token by encrypting user's id + time as JSON

我正在制作一个 API 并且 我是新手 。我想到了创建访问令牌的想法。基本上,我们用密钥加密 JSON 数据,将其转换为 Base64 并将其 return 作为访问令牌。稍后,API 解密该访问令牌并可以使用该 ID。例如:

login method: 我们检查 username/password 是否正确,如果正确,则我们从数据库中获取用户 ID。然后我们构建访问令牌,它将在以后的API调用中使用,像这样:

  1. 我们制作一个 JSON 字符串,例如{"user_id":609, "logintime":"1430428180"}
  2. 我们使用加密函数(例如 these)并使用我们的加密密钥加密 JSON 字符串。
  3. 我们将加密字符串转换为 Base64,因此它是可读的并且return将其作为访问令牌。

稍后,当用户进行操作时,我们可以使用此访问令牌来了解用户。例如:

update user info method:我们发送需要更新的数据和我们之前获得的访问令牌。那么我们:

  1. Base64 解码访问令牌。
  2. 使用我们的加密密钥对其进行解密。
  3. 解析JSON数据,我们知道用户的id,所以我们可以很容易地更新数据库。此外,我们知道 API 调用是合法的,因为解密的字符串是 JSON 并且它包含 user_idlogintime 字段。

这个方法好用吗?

当涉及身份验证、访问令牌等方面时,您通常最好使用一个比我们都聪明得多的人创建的经过验证的库。

Json Web Tokens or JWT, were created to solve exactly this sort of problem (among others). And it has a PHP library.

因此,为用户创建访问令牌如下所示。 (解释自述文件)

<?php

$key = "my-secret-key-here";
$token = array(
    "user_id" => 1
);

$jwt = JWT::encode($token, $key);

/**
  * $jwt is your JSON web token, it will look something like this:
  *
  * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMSJ9.TcXz_IwlmxO5nPd3m0Yo67WyYptabkqZW4R9HNwPmKE
  *
  **/

$decoded = JWT::decode($jwt, $key, array('HS256'));

print_r($decoded);

/*
 NOTE: This will now be an object instead of an associative array. To get
 an associative array, you will need to cast it as such:
*/

$decoded_array = (array) $decoded;

?>

因此,在回答您的问题时,您的方向是正确的! JWT 似乎完全符合您在此处描述的内容,因此我会选择经过更彻底测试的库的安全性。

在这个答案中,我将更多地关注 API 安全性,我认为这是问题背后的真正问题(由 OP 对我的第一个答案的评论提示)。

API 键的用途

API 密钥用于用户登录困难、不可能或不希望登录的情况。 API 密钥用于 Authentication,API 访问的 "proof of who I am" 部分。 授权,或者"I am allowed to do this"通常存储在服务器上。

有效 API 访问条件

为了让您确信请求有效,您必须考虑两点。

  1. 请求是否来自授权用户?
  2. 请求是否在传输过程中被篡改?

为了确保第 1 点随着时间的推移成立,API 还应该担心密钥 保持 秘密。

  1. 此请求不会损害以后请求的有效性。

请注意,虽然 API 密钥通常作为 HTTP headers 发送,但为了简单起见,我将在示例中使用 GET 变量。

单键API

一些 API 设置为使用单个密钥进行访问。让我们使用 CEgJu8G483u3 作为示例键。

用户会发送类似

的请求
GET /users?apiKey=CEgJu8G483u3 HTTP/1.1
Host: api.bigorg.com

如果 API 通过 HTTP 通信,这 本质上 不安全:

  1. 任何爱管闲事的第 3 方都可以公开读取(因此可以使用)该密钥。
  2. 第3方可以随意篡改请求的body,而服务器是不知道的。

因此在通过 HTTP 的单密钥 API 身份验证中,违反了安全标准 1 - 3。

如果您的单个密钥 API 仅通过 HTTPS 进行通信,那么 1 - 3 仍然有效并且可以被认为是安全的。

摘要或签名APIs

这种方法被 Google 和亚马逊用于访问他们的许多 API。

当服务器授予对其系统的访问权限时,会生成 两个 密钥,一个 identifier 和一个 secret.

ACCESS_IDENTIFIER = 'bill';
ACCESS_SECRET = 'U59g5LcBBZpw';

一旦生成了两个密钥,客户端和服务器就会存储一份秘密副本,永远不会再直接传输。

当在该系统下发出请求时,标识符随请求一起提供(请注意,访问密钥可以像随机生成的字符串一样复杂,也可以像尝试访问的用户的id一样简单系统.

就在客户端发送请求之前,会生成请求的摘要,然后使用先前商定的秘密对其进行加密。生成签名的方法多种多样,但目前常见的是HMAC

然后请求看起来像这样

     GET /users?identifier=bill&signature=JjU1j1fIH62KG7FCTdZGzK7J HTTP/1.1
     Host: api.bigorg.com

本例中使用的随机pseudo-signature

如果在生成签名时包含请求 body,您现在可以安全地进行身份验证。

请注意,监听HTTP流量仍然非常非常简单,因此未经授权的知识仍然是一个问题,但监听方无法发送自己的请求或篡改您的请求。

如果请求被篡改,签名将失效,请求将被拒绝。

JSON Web 令牌(您的解决方案)

您的解决方案与 JSON Web Tokens 几乎相同,所以我假设您正在使用它。

此解决方案通过 HTTPS 是安全的。 (DO 使用 HTTPS)

  1. 请求来自有效用户=> 他们知道令牌
  2. 请求未被篡改 => HTTPS 防止第 3 方篡改请求
  3. 访问密钥保密 => HTTPS 防止第 3 方读取您的访问密钥

如果您的 API 使用 HTTP/plaintext,您可以使用 JSON Web 令牌作为访问密钥,但您还需要生成一个私人秘密并使用它为请求添加签名。

请注意,如果您使用 HTTP,我不确定您将如何将机密传输到客户端。也许通过蜗牛邮件或电子邮件?

结论

你的想法已经被非常聪明的人复制了。恭喜!这意味着这是个好主意!

如果您使用 HTTPS,您的访问密钥解决方案是可靠的。