php REST API 授权和身份验证(网络 + 移动)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9386930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 06:41:51  来源:igfitidea点击:

REST API Authorization & Authentication (web + mobile)

phpapiauthenticationrestauthorization

提问by svenkapudija

I've read about oAuth, Amazon REST API, HTTP Basic/Digest and so on but can't get it all into "single piece". This is probably the closest situation - Creating an API for mobile applications - Authentication and Authorization

我已经阅读了有关 oAuth、Amazon REST API、HTTP Basic/Digest 等的内容,但无法将其全部整合到“单一部分”中。这可能是最接近的情况 -为移动应用程序创建 API - 身份验证和授权

I would like to built API-centric website - service. So (in the beginning) I would have an API in center and website(PHP + MySQL) would connect via cURL, Androidand iPhonevia their network interfaces. So 3 main clients - 3 API keys. And any other developer could also develop via API interface and they would get their own API key. API actions would be accepted/rejected based on userLevel status, if I'm an admin I can delete anything etc., all other can manipulate only their local (account) data.

我想建立以 API 为中心的网站 - 服务。所以(一开始)我会在中心有一个 API,网站(PHP + MySQL)将通过cURLAndroidiPhone通过它们的网络接口连接。所以 3 个主要客户端 - 3 个 API 密钥。任何其他开发人员也可以通过 API 接口进行开发,他们将获得自己的 API 密钥。API 操作将根据 userLevel 状态被接受/拒绝,如果我是管理员,我可以删除任何内容等,所有其他人只能操作他们的本地(帐户)数据。

First, authorization - should I use oAuth + xAuth or my some-kind-of-my-own implemenation (see http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/RESTAuthentication.html?r=9197)? As I understand, on Amazon service user is == API user (have API key). On my service I need to separate standard users/account (the one who registered on the website) and Developer Accounts (who should have their API key).

首先,授权 - 我应该使用 oAuth + xAuth 还是我自己的某种实现(参见http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/RESTAuthentication.html?r=9197)?据我了解,亚马逊服务用户是 == API user (have API key)。在我的服务中,我需要将标准用户/帐户(在网站上注册的那个)和开发者帐户(应该拥有他们的 API 密钥)分开。

So I would firstly need to authorize the API keyand then Authenticate the useritself. If I use Amazon's scheme to check developer's API keys (authorize their app), which sheme should I use for user authentication?

所以我首先需要授权 API 密钥,然后对用户本身进行身份验证。如果我使用亚马逊的方案来检查开发者的 API 密钥(授权他们的应用程序),我应该使用哪个方案进行用户身份验证?

I read about getting a token via api.example.org/authafter (via HTTPS, HTTP Basic) posting my username and password and then forward it on every following request. How manage tokens if I'm logged in simultaneously on Androidand a website? What about man-in-the-middle-attack if I'm using SSL only on first request (when username and password are transmitted) and just HTTP on every other? Isn't that a problem in this example Password protecting a REST service?

我读到了通过api.example.org/auth(通过HTTPS,HTTP Basic)发布我的用户名和密码来获取令牌,然后在每个后续请求中转发它。如果我同时登录Android网站,如何管理令牌?如果我仅在第一次请求时使用 SSL(传输用户名和密码时),并且每隔一个使用 HTTP,那么中间人攻击呢?在这个例子中,这不是一个问题吗?密码保护 REST 服务?

回答by Eugen Rieck

As allways, the best way to protect a key is not to transmit it.

一如既往,保护密钥的最佳方法是不传输它。

That said, we typically use a scheme, where every "API key" has two parts: A non-secret ID (e.g. 1234) and a secret key (e.g. byte[64]).

也就是说,我们通常使用一种方案,其中每个“API 密钥”都有两部分:非秘密 ID(例如 1234)和秘密密钥(例如字节 [64])。

  • If you give out an API key, store it (salted and hashed) in you service's database.
  • If you give out user accounts (protected by password), store the passwords (salted and hashed) in your service's database
  • 如果您提供 API 密钥,请将它(加盐和散列)存储在您的服务数据库中。
  • 如果您提供用户帐户(受密码保护),请将密码(加盐和散列)存储在您的服务数据库中

Now when a consumer firstaccesses your API, to connect, have him

现在,当消费者第一次访问您的 API 时,要连接,让他

  • Send a "username" parameter ("john.doe" not secret)
  • Send a "APIkeyID" parameter ("1234", not secret)
  • 发送“用户名”参数(“john.doe”不是秘密)
  • 发送“APIkeyID”参数(“1234”,不是秘密)

and give him back

并把他还给

  • the salts from your database (In case one of the parameters is wrong, just give back some repeatable salt - eg. sha1(username+"notverysecret").
  • The timestamp of the server
  • 数据库中的盐(如果其中一个参数错误,只需返回一些可重复的盐 - 例如 sha1(用户名+“notverysecret”)。
  • 服务器的时间戳

The consumer should store the salt for session duration to keep things fast and smooth, and he should calculate and keep the time offset between client and server.

消费者应该在会话期间存储盐以保持快速和流畅,并且他应该计算并保持客户端和服务器之间的时间偏移。

The consumer should now calculate the salted hashes of API key and password. This way the consumer has the exact same hashes for password and API key, as what is stored in your database, but without anything seceret ever going over the wire.

消费者现在应该计算 API 密钥和密码的加盐哈希。通过这种方式,消费者对密码和 API 密钥拥有与存储在数据库中完全相同的哈希值,但没有任何秘密通过网络传输。

Now when a consumer subseqentlyaccesses your API, to do real work, have him

现在,当消费者随后访问您的 API 以进行实际工作时,让他

  • Send a "username" parameter ("john.doe" not secret)
  • Send a "APIkeyID" parameter ("1234", not secret)
  • Send a "RequestSalt" parameter (byte[64], random, not secret)
  • Send a "RequestTimestamp" parameter (calculated from client time and known offset)
  • Send a "RequestToken" parameter (hash(passwordhash+request_salt+request_timestamp+apikeyhash))
  • 发送“用户名”参数(“john.doe”不是秘密)
  • 发送“APIkeyID”参数(“1234”,不是秘密)
  • 发送“RequestSalt”参数(字节[64],随机,非秘密)
  • 发送“RequestTimestamp”参数(根据客户端时间和已知偏移量计算)
  • 发送“RequestToken”参数(hash(passwordhash+request_salt+request_timestamp+apikeyhash))

The server should not accept timestamps more than say 2 seconds in the past, to make this safe against a replay attack.

服务器不应接受超过过去 2 秒的时间戳,以使其免受重放攻击。

The server can now calculate the same hash(passwordhash+request_salt+request_timestamp+apikeyhash) as the client, and be sure, that

服务器现在可以计算与客户端相同的哈希(passwordhash+request_salt+request_timestamp+apikeyhash),并确保,

  • the client knows the API key,
  • the client knows the correct password
  • 客户端知道 API 密钥,
  • 客户端知道正确的密码