验证在REST Web服务 [英] Authentication in RESTful web services

查看:108
本文介绍了验证在REST Web服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在建立一个网站,用户可以查看和修改他们的小部件。存储我的服务器上的小部件的数据全部互为作用将通过REST Web服务来完成。例如,如果用户希望看到自己的小部件列表执行流程是这样的:

I am currently creating a website which users can view and modify their widgets. All interation with the widget data stored on my server will be done through RESTful web services. For example, if a user wants to see a list of their widgets the flow of execution would be something like:


  1. 用户访问12345 https://www.example.com/Login.htm 和(通过OpenID提供商在我的情况)与服务器进行身份验证

  2. 用户12345然后访问该页面 https://www.example.com/Widgets.htm

  3. 服务器与一个HTML页面和JavaScript将被用来访问我的Web服务的响应。

  4. 当HTML页面加载JavaScript函数的getWidgets()将被调用。 的getWidgets()将调用我的web服务 https://www.example.com/Services/Widget/12345

  5. 服务与用户控件列表响应该另一个JavaScript函数 renderWidgets(小工具)将更新HTML页面

  1. User 12345 accesses https://www.example.com/Login.htm and authenticates with the server (in my case through an OpenID provider)
  2. User 12345 then accesses the page https://www.example.com/Widgets.htm
  3. Server responds with an HTML page and javascript that will be used to access my web services.
  4. When the HTML page has loaded the javascript function getWidgets() will be called. getWidgets() will call my web service https://www.example.com/Services/Widget/12345
  5. The service responds with a list of the users widgets which another javascript function renderWidgets(widgets) will update the html page

我不希望任何人,但用户访问12345自己的小部件,所以我猜的getWidgets()将必须提供一些认证到我的Web服务。我不知道什么是最好的办法是实现这一目标。

I don't want anyone else but user 12345 accessing their own widgets so I guess getWidgets() will have to provide some authentication to my web service. I'm not sure what the best way would be to achieve this.

我在想,客户端和服务器可以有一个共享的秘密的getWidgets()将发送到Web服务。该服务器可以生成这个秘密的随机字符串(数字,GUID或其他),它包括在响应头当客户端请求的初始HTML页面。发送请求到服务器时,客户端将使用该密钥。

I was thinking that the client and server could have a shared secret that getWidgets() will send to the web service. The server could generate this secret as random string (number, GUID or whatever) and include it in the response header when the client requests the initial HTML page. The client would use this secret key when sending requests to the server.

这听起来像一个明智的想法?

Does this sound like a sensible idea?

这是一个共同的要求那么有没有达到同样的事情的标准方式吗?据我所知,这是的OpenID和OAuth的范围之外将不适合。

This is a common requirement so is there a standard way of achieving the same thing? As far as I am aware this is outside of the scope of OpenID and OAuth would not be suitable.

先谢谢了。

推荐答案

这是一个很大的问题 - 但我认为您的解决方案可能需要多一点复杂得多,你在想

This is a great question - but I think your solution may need to be a bit more complex than you are thinking.

在一般情况下,要在其中进行验证这种情形的方式是在一个2级交换。第一步是为应用程序提供服务器的私有密钥(由服务器特有的客户端应用生成)来验证,这是,实际上,一个有效的客户端。这是提供权威的证据来您的服务器请求来自它知道和可以信任的软件来了。

In general, the way in which you want to authenticate this kind of scenario is in a 2-stage handshake. The first step is for your application to provide the server a private key (generated by the server, unique to the client application) to authenticate that it is, in fact, a valid client. This is what provides authoritative evidence to your server that the request is coming from software it knows and can trust.

第二步,那么,当用户去登录到您的客户端应用程序,他们提供了一个用户名/密码组合。这些信息与您的应用程序密钥一起,都应该可以通过SSL发送到服务器。

The second step, then, is that when a user goes to log in to your client application, they provide a username / password combination. This information, along with your application key, should all be sent up to the server via SSL.

SSL加密数据,以便第三方使用数据包嗅探器无法读取在途的数据,服务器执行以下操作:

SSL encrypts the data so that a third-party with a packet-sniffer can't read the data in-transit, and the server does the following:


  1. 检查应用程序的关键是有效的。

  2. 验证该用户名存在,并与应用程序相关联。

  3. 加密的密码,并测试对在数据库中的加密版本的加密版本,与用户名相关联。

  4. 如果所有的上面列出的检查都通过了,服务器返回一个会话ID,它可以放入一个客户端cookie - 并用每个后续请求重新进行身份验证的用户。 如果有任何测试失败 - 服务器返回一个 401:未经授权响应,或其他类似的错误

  1. Checks that the application key is valid.
  2. Validates that the username exists, and is associated with the application.
  3. Encrypts the password and tests the encrypted version against the encrypted version in the database, associated with the username.
  4. IF ALL of the above-listed checks pass, the server returns a session ID, which can be put into a client-side cookie - and used to re-authenticate the user on each subsequent request. IF ANY of the tests fail - the server returns a 401: Unauthorized response, or other similar error.

此时,客户端可以利用返回的会话ID,而不必继续重新提交应用密钥

At this point, the client can utilize the returned session ID without having to continue to re-submit the application key.

您的应用程序

现在,你的情况,你可能会实际上托管在同一个应用程序,并在同一台服务器上的客户端/服务器。在这种情况下 - 你可以跳过通常所有的碎片周围的专用密钥旋转 - 而且只是简单地不允许跨站点脚本请求,而不是

Now, in your case, you may be actually hosting the client/server in the same application and on the same server. In this case - you can generally skip all of the pieces revolving around the private application key - and simply disallow cross-site script requests instead.

为什么的 - 因为你真的防止事情是如下:

Why? - because the thing you're really protecting against is the following:

服务器A承载您的RESTful API。
客户B,C和D的主机客户,这将依赖于服务器A的API。你不想要的是客户端E(不是你的应用程序 - 和恶意),能够要么绕过或者盗窃其他客户之一的凭据来访问服务器A

Server A hosts your RESTful API. Client's B, C and D host clients which will rely upon Server A's API. What you don't want is for Client E (not your application - and malicious) to be able to access Server A either by bypassing or stealing the credentials of one of the other Clients.

但是,如果客户端和服务器都托管在同一个地方,因此具有相同的URL - 即基于REST的API驻留在 www.yourdomain.com/api 和客户端驻留在 www.yourdomain.com / - 一般来说您可以不允许那些源自 yourdomain.com之外的任何AJAX类型的请求 - 那就是你的安全层

If, however, both client and server are hosted in the same place, and therefore have the same URL - i.e. the RESTful API resides at www.yourdomain.com/api and the client resides at www.yourdomain.com/ - you can generally just not allow any AJAX type requests which originate outside of yourdomain.com - and that is your layer of security.

在这种情况下,以下是你应该需要做的,有合理的安全级别:

In this case, the following is all you should need to do to have a reasonable level of security:


  1. 为您的服务器启用SSL。

  2. 仅允许请求 /认证/登录(或任何你登录 POST 方法),以通过SSL来(在C#这可以通过使用方法或控制器 [RequireHttps] 属性来完成)。

  3. 拒绝这源于自己的域名之外的任何AJAX请求。

  4. 在您的Cookie使用加密层。

  1. Enable SSL for your server.
  2. Only allow requests to /auth/login (or whatever your login POST method is) to come via SSL (in C# this can be done by using the [RequireHttps] attribute on the method or controller).
  3. Reject any AJAX requests which originate outside your own domain.
  4. Use a layer of encryption in your cookie.

你应该你的cookie包含哪些内容?

在理想情况下,该Cookie应该包含2路,只有你的服务器可以解密加密的数据。换句话说 - 你可以把类似的用户的用户名 USER_ID 饼干里 - 但2路进行加密使用Rijndael算法或其它密码系统 - 使用只有你的服务器可以访问(我建议字符的随机字符串)加密密码

Ideally, the cookie should contain 2-way encrypted data that ONLY your server can decrypt. In other words - you might put something like the user's username or user_id inside the cookie - but 2-way encrypt it using Rijndael or another cryptography system - using an encryption password that only your server has access to (I suggest a random string of characters).

然后 - 当您收到后续请求附有该cookie,你可以简单地做到以下几点:

Then - when you receive subsequent requests with the cookie attached, you can simply do the following:


  1. 如果cookie的存在,尝试用你的私人密码进行解密。

  2. 如果产生的解密数据就是垃圾 - 抛出一个 401:未经授权反应(这是一个改变的或伪造的cookie)

  3. 如果产生的解密数据是用户名相匹配的数据库 - 你现在知道是谁发出请求 - 并且可以过滤/据此为他们服务的数据

  1. If the cookie exists, attempt to decrypt it using your private password.
  2. If the resulting decrypted data is garbage - throw a 401: Unauthorized response (this is an altered or fake cookie)
  3. If the resulting decrypted data is a username which matches your database - you now know who is making the request - and can filter / serve them data accordingly.

我希望这有助于。 :)如果没有 - 随意张贴任何意见和提问,我会试图澄清

I hope this helps. :) If not - feel free to post any comments and ask questions, and I'll try to clarify.

这篇关于验证在REST Web服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆