将 api 密钥传递给 rest api

Posted

技术标签:

【中文标题】将 api 密钥传递给 rest api【英文标题】:Passing api keys to rest api 【发布时间】:2012-01-23 22:45:19 【问题描述】:

我正在使用 phil sturgeon REST_Controller 为 codeigniter 创建一个 REST api,到目前为止,我已经能够创建一个简单的库来为用户生成 api 密钥。 我现在的问题是为每个请求将 api 密钥发送到 API,我如何做到这一点而不必为每个请求手动发送它。

【问题讨论】:

【参考方案1】:

您应该查看请求签名。一个很好的例子是Amazon's S3 REST API。

概述实际上非常简单。用户有两个重要的信息可以使用您的 API,一个公共用户 ID 和一个私有 API 密钥。他们将公共 ID 与请求一起发送,并使用私钥对请求进行签名。接收服务器查找用户的密钥并确定签名请求是否有效。流程是这样的:

    用户加入您的服务并获得用户 ID(例如 123)和 API 键。 用户想要向您的 API 服务发出请求以更新他们的电子邮件地址,因此他们需要向您的 API 发送请求,也许是 /user/update?email=new@example.com。 为了能够验证请求,用户在调用中添加了用户 ID 和 签名,因此调用变为 /user/update?email=new@example.com&userid=123&sig=some_generated_string 服务器接收到调用,发现它来自 userid=123,并查找该用户的 API 密钥。然后它复制从数据创建签名的步骤,如果签名匹配,则 请求有效。

此方法可确保 API 密钥永远不会作为通信的一部分发送

看看 php 的 hash_hmac() 函数,它在发送签名请求时很受欢迎。通常,您会让用户执行一些操作,例如将所有参数放入一个数组中,按字母顺序排序,连接成一个字符串,然后 hash_hmac 该字符串以获取 sig。在此示例中,您可能会这样做:

$sig = hash_hmac("sha256",$params['email'].$params['userid'],$API_KEY)

然后如上所述将$sig 添加到 REST url。

【讨论】:

只是想理解这一点,因为我正在尝试做这样的事情.../user/update?email=new@example.com&userid=123&sig=some_generated_string 现在不能有人劫持some_generated_string 并发送它,就好像它来自他们自己一样? (我敢肯定他们不能,但也许你能告诉我为什么?) @jasondavis - 是的,有人可以嗅探那个特定的请求,这是真的。但是因为每个请求的签名都是不同的,所以嗅探它们并没有什么好处。充其量,他们所能做的就是发送完全相同的请求!他们无法生成恶意请求,因为要做到这一点,您需要 API 密钥。如果他们试图破坏他们嗅探到的请求中的数据,比如将电子邮件更改为evil@example.com,签名将不再匹配,并且 REST 服务器将在尝试验证请求时拒绝该请求。 如果用户从 javascript 发出请求并因此将他们的 API 密钥暴露给全世界,这种方法是否不安全?有人可以查看源代码、获取 API 密钥并使用相同的方法生成有效请求以调用服务器。还是我错过了什么。 @zombat (我不这么认为,但无论如何..)当用户填写 html 表单时,有没有办法做到这一点?当我说“用户”时,我指的是注册用户,而不是通过存储秘密 api 密钥的本地 PHP 文件发送请求的开发人员。如果没有,我该怎么办? @zombat 这是 baris-usakli 提出的一个非常好的问题。如何在 javascript Web 应用程序中隐藏 API 密钥?对于使用相同 API 的手机应用市场,即使有如何为每个下载的手机应用创建私有 API 并让 API 知道呢?【参考方案2】:

REST 的理念是它是无状态的,因此没有会​​话或任何东西。如果您想进行身份验证,那么这就是密钥的来源,并且必须为每个请求传递密钥,并且每个请求都会对用户进行身份验证(因为 REST 是无状态的,我是否提到过这一点?)。

您可以通过多种方式传递密钥。您可以将其作为参数传递(即http://example.com/api/resource/id?key=api_key),也可以将其作为 HTTP 标头的一部分传递。我见过指定您发送用户名和 API 密钥作为 HTTP 基本访问授权标头的密码部分的 API。

一个示例请求:

<?php

$ch = curl_init();
curl_setopt_array($ch, array(
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_URL => 'http://example.com/api/resource/id',
    CURLOPT_USERPWD => 'martinbean:4eefab4111b2a'
));
$response = curl_exec($ch);

martinbean 是我在您网站上的帐户用户名,4eefab4111b2a 是我的 API 密钥。

【讨论】:

这种方法很简单,但本质上是不安全的。有人可以轻松地嗅探您的 API 密钥并开始为自己使用它。如果您希望您的 API 密钥是私有的,您不希望将它们作为请求的一部分发送。 适用于活动监视器:campaignmonitor.com/api/getting-started/#authentication Campaign Monitor 将在他们的客户第一次因为在星巴克使用开放无线连接而被劫持 API 密钥时进行大量解释。 访问令牌是一种常用方法,但 API 密钥不是。访问令牌过期,所以如果一个被泄露,它不会是一个大的安全漏洞。但是如果我有你的 API 密钥,我可以生成任意数量的访问令牌。所有这些服务都给你一个“秘密”密钥是有充分理由的……它应该是一个秘密。任何让您传递密钥的服务都是错误的。 请注意,Campaign Monitor(截至 2017 年)使用 HTTPS URL 来传递其 API 密钥,因此它是安全的。不确定这在 2011 年是否属实,当时@zombat 指出这样做很危险。

以上是关于将 api 密钥传递给 rest api的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 process.env 将环境变量中的 API 密钥传递给 Ember CLI?

RESTful API 中的 API 密钥加密?

如何在Woocommerce Rest API中获取Tokenization密钥?

如何在 Vue 中将 API 应用程序密钥作为道具传递

REST API 和 API KEY

使用 REST 客户端 POSTMAN 使用 api 密钥调用 AWS api 网关端点