确保 REST API 安全,无需重新发明轮子
在设计 REST API 时,通常首先对用户进行身份验证吗?
我正在寻找的典型用例是:
- 用户想要获取数据。当然很酷,我们喜欢分享!获取公共 API 密钥并阅读!
- 用户想要存储/更新数据...哇等等!你是谁,你能做到吗?
我想构建一次并允许 Web 应用程序、Android 应用程序或 iPhone 应用程序使用它。
REST API 似乎是满足这样的要求的逻辑选择
为了说明我的问题,我将使用一个简单的示例。
我的数据库中有一个项目,它具有 评级 属性(整数 1 到 5)。
如果我正确理解 REST,我将使用我选择的返回 csv、xml 或 json 的语言实现 GET 请求,如下所示:
http://example.com/product/getrating/{id}/
假设我们选择返回的 JSON:
{
"id": "1",
"name": "widget1",
"attributes": { "rating": {"type":"int", "value":4} }
}
这对于面向公众的 API 来说很好。我明白那部分。
我有很多问题是如何将其与安全模型结合起来?我习惯了网络应用程序安全性,我有一个会话状态可以随时识别我的用户,这样我就可以控制他们可以做什么,无论他们决定向我发送什么。据我了解,这不是 RESTful,所以在这种情况下这将是一个糟糕的解决方案。
我将尝试使用另一个使用相同项目/评级的示例。
如果用户“JOE”想要向
可以使用以下方法完成:
http://example.com/product/addrating/{id}/{givenRating}/
此时,我想存储“JOE”给出产品{的数据id} 评分为 {givenRating}。
问题:我如何知道请求来自“JOE”而不是“BOB”。
此外,如果是为了更敏感的数据(例如用户的电话号码)怎么办?
到目前为止我所得到的是:
1) 使用 HTTP 的内置功能对每个请求进行身份验证,无论是纯 HTTP 还是 HTTPS。
这意味着现在每个请求都采用以下形式:
https://joe:[email protected]/product/addrating/{id}/{givenRating}/
2) 使用 Amazon S3 等带有私钥和公钥的方法: http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
3)无论如何都使用cookie并打破无状态部分休息。
第二种方法对我来说似乎更好,但我想知道我是否真的必须重新发明整个事情?散列、存储、生成密钥等全部由我自己完成吗?
这听起来很像在典型的 Web 应用程序中使用会话并自己重写整个堆栈,这对我来说通常意味着“你做错了”,尤其是在处理安全性时。
编辑:我想我也应该提到 OAuth。
When designing REST API is it common to authenticate a user first?
The typical use case I am looking for is:
- User wants to get data. Sure cool we like to share! Get a public API key and read away!
- User wants to store/update data... woah wait up! who are you, can you do this?
I would like to build it once and allow say a web-app, an android application or an iPhone application to use it.
A REST API appears to be a logical choice with requirements like this
To illustrate my question I'll use a simple example.
I have an item in a database, which has a rating attribute (integer 1 to 5).
If I understand REST correctly I would implement a GET request using the language of my choice that returns csv, xml or json like this:
http://example.com/product/getrating/{id}/
Say we pick JSON we return:
{
"id": "1",
"name": "widget1",
"attributes": { "rating": {"type":"int", "value":4} }
}
This is fine for public facing APIs. I get that part.
Where I have tons of question is how do I combine this with a security model? I'm used to web-app security where I have a session state identifying my user at all time so I can control what they can do no matter what they decide to send me. As I understand it this isn't RESTful so would be a bad solution in this case.
I'll try to use another example using the same item/rating.
If user "JOE" wants to add a rating to an item
This could be done using:
http://example.com/product/addrating/{id}/{givenRating}/
At this point I want to store the data saying that "JOE" gave product {id} a rating of {givenRating}.
Question: How do I know the request came from "JOE" and not "BOB".
Furthermore, what if it was for more sensible data like a user's phone number?
What I've got so far is:
1) Use the built-in feature of HTTP to authenticate at every request, either plain HTTP or HTTPS.
This means that every request now take the form of:
https://joe:[email protected]/product/addrating/{id}/{givenRating}/
2) Use an approach like Amazon's S3 with private and public key: http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
3) Use a cookie anyway and break the stateless part of REST.
The second approach appears better to me, but I am left wondering do I really have to re-invent this whole thing? Hashing, storing, generating the keys, etc all by myself?
This sounds a lot like using session in a typical web application and rewriting the entire stack yourself, which usually to me mean "You're doing it wrong" especially when dealing with security.
EDIT: I guess I should have mentioned OAuth as well.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
5年后编辑
使用OAuth2!
以前的版本
不,绝对不需要使用cookie。它的安全性还不及 HTTP Digest、OAuth 或 Amazon 的 AWS(这并不难复制)。
您应该看待 cookie 的方式是,它与 Basic/Digest/OAuth/ 中的任何一个一样都是身份验证令牌,但不太合适。
不过,我不认为使用 cookie 本身就违反了 RESTful 原则,只要会话 cookie 的内容不会影响从服务器返回的资源内容即可。
Cookie 是邪恶的,停止使用它们。
Edit 5 years later
Use OAuth2!
Previous version
No, there is absolutely no need to use a cookie. It's not half as secure as HTTP Digest, OAuth or Amazon's AWS (which is not hard to copy).
The way you should look at a cookie is that it's an authentication token as much as Basic/Digest/OAuth/whichever would be, but less appropriate.
However, I don't feel using a cookie goes against RESTful principles per se, as long as the contents of the session cookie does not influence the contents of the resource you're returning from the server.
Cookies are evil, stop using them.
不要担心“RESTful”,担心安全。我是这样做的:
第 1 步:用户使用凭据访问身份验证服务。
第 2 步:如果凭据签出,则返回指纹、会话 ID 等...,并将它们弹出到共享内存中以便稍后快速检索,或者如果您不介意在 Web 服务周转时间上增加几毫秒,则使用数据库。
步骤 3:将入口点调用添加到每个 Web 服务脚本的顶部,以验证每个 Web 服务请求的指纹和会话 ID。
步骤 4:如果指纹和会话 ID 无效或超时,则重定向到身份验证。
阅读本文:
RESTful 身份验证
Don't worry about being "RESTful", worry about security. Here's how I do it:
Step 1: User hits authentication service with credentials.
Step 2: If credentials check out, return a fingerprint, session id, etc..., and pop them into shared memory for quick retrieval later or use a database if you don't mind adding a few milliseconds to your web service turnaround time.
Step 3: Add an entry point call to the top of every web service script that validates the fingerprint and session id for every web service request.
Step 4: If the fingerprint and session id aren't valid or have timed out redirect to authentication.
READ THIS:
RESTful Authentication
3年后编辑
我完全同意Evert的观点,使用OAuth2和HTTPS,并且不要重新发明轮子! :-)
通过更简单的 REST API - 不适用于第 3 方客户端 - JSON Web 令牌 也可以很好。
以前的版本
不要使用会话,使用会话,您的 REST 服务将无法很好地扩展...这里有 2 种状态:应用程序状态(或客户端状态或会话)和资源状态。应用程序状态包含会话数据,由 REST 客户端维护。资源状态包含资源属性和关系,由 REST 服务维护。您可以非常轻松地决定特定变量是应用程序状态还是资源状态的一部分。如果数据量随着活动会话数的增加而增加,那么就属于应用程序状态。例如,当前会话的用户身份属于应用程序状态,但用户或用户权限的列表属于资源状态。
因此,REST 客户端应该存储标识因素并在每次请求时发送它们。不要将 REST 客户端与 HTTP 客户端混淆。它们不一样。如果 REST 客户端使用curl,它也可以位于服务器端,或者它可以创建一个服务器端仅 http 的 cookie,它可以通过 CORS 与 REST 服务共享。唯一重要的是 REST 服务必须对每个请求进行身份验证,因此您必须在每个请求中发送凭据(用户名、密码)。
状态:401未经授权
响应...饼干不一定是坏事。您可以以 RESTful 方式使用它们,直到它们保存客户端状态并且服务仅保存资源状态。例如,您可以将购物车或首选分页设置存储在 cookie 中...
Edit 3 years later
I completely agree with Evert, use OAuth2 with HTTPS, and don't reinvent the wheel! :-)
By simpler REST APIs - not meant for 3rd party clients - JSON Web Tokens can be good as well.
Previous version
Don't use sessions, with sessions your REST service won't be well scalable... There are 2 states here: application state (or client state or session s) and resource state. Application state contains the session data and it is maintained by the REST client. Resource state contains the resource properties and relations and is maintained by the REST service. You can decide very easy whether a particular variable is part of the application state or the resource state. If the amount of data increases with the number of active sessions, then it belongs to the application state. So for example user identity by the current session belongs to the application state, but the list of the users or user permissions belongs to the resource state.
So the REST client should store the identification factors and send them with every request. Don't confuse the REST client with the HTTP client. They are not the same. REST client can be on the server side too if it uses curl, or it can create for example a server side http only cookie which it can share with the REST service via CORS. The only thing what matters that the REST service has to authenticate by every request, so you have to send the credentials (username, password) with every request.
credentials -> (identity, permissions)
cache on the server to make authentication faster. Be aware of that if you clear that cache, and the users send the same request, they will get the same response, just it will take a bit longer. You can compare this with sessions: if you clear the session store, then users will get astatus: 401 unauthorized
response...Cookies are not necessarily bad. You can use them in a RESTful way until they hold client state and the service holds resource state only. For example you can store the cart or the preferred pagination settings in cookies...