Authentication in RESTful web services

前端 未结 3 944
野的像风
野的像风 2020-12-31 09:21

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 ser

相关标签:
3条回答
  • 2020-12-31 10:01

    I don't know much about security, but i think it all depends on how much time/cost you are willing to spend (keeping in mind that everything is hackable).

    As concerned of security as you are, you probably protected your session variables, the easiest thing you can do is an ajax call to a server action in which you check for the session and compare it with user request.

    0 讨论(0)
  • 2020-12-31 10:08

    Is this not as simple as MACing the request to the web service?

    So, you're providing the JavaScript that calls the web service, within this JavaScript you put a nonce. Unlike most nonce implementations, you have this live for the duration of the user session.

    When calling the web service, the JavaScript in GetWidgets() uses the nonce as the key to hash some 'random' data, I'd probably use the time formatted as a string and the data, the user's id (12345) as the salt. The JavaScript then sends the hashed data and the unhashed time string as part of the web service call, but not the nonce. I'd then ensure the time that was sent was recent (i.e. last 20 seconds, limiting replay attacks) and that when the server hashes the time with the user id as salt with the nonce (that it knows because it set it) that it gets the same result.

    So, we've used a shared key set by the server and sent to the client to act as the key for producing a hashed message authorization code (MAC or HMAC) but also prevented replay attacks (the MAC will be different for each request and has a very short replay window) and preventing session hijacking by not transferring any session information in cookies.


    I've not come across your specific scenario before, but it does seem like a specific case of a generic problem of authenticating messages without wanting to send credentials with every message. MACing is reliably how I've seen this done.

    See: http://en.wikipedia.org/wiki/Message_authentication_code, this gives a good overview on MACing and even includes a nice diagram to help explain. It's a fairly well trodden solution, the only deviation I'd recommend (because I've fallen foul of it) is to include the time in the message to prevent replays.

    It's the basis of the approach used by Last.fm to help authorize access to their API, see part 8 on this page (Signing Calls): http://www.last.fm/api/authspec#8. The Hash they're using is MD5, the querystring is being included in the body text to be hashed and the secret being used a session key obtained from an initial authenticate call.

    0 讨论(0)
  • 2020-12-31 10:11

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

    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.

    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 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. 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.

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

    Your Application

    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:

    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.

    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. 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.

    What should your cookie contain?

    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).

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

    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.

    0 讨论(0)
提交回复
热议问题