RESTful Authentication

前端 未结 14 2021
死守一世寂寞
死守一世寂寞 2020-11-21 22:56

What does RESTful Authentication mean and how does it work? I can\'t find a good overview on Google. My only understanding is that you pass the session key (remeberal) in

相关标签:
14条回答
  • 2020-11-21 23:25

    I doubt whether the people enthusiastically shouting "HTTP Authentication" ever tried making a browser-based application (instead of a machine-to-machine web service) with REST (no offense intended - I just don't think they ever faced the complications).

    Problems I found with using HTTP Authentication on RESTful services that produce HTML pages to be viewed in a browser are:

    • user typically gets an ugly browser-made login box, which is very user-unfriendly. you cannot add password retrieval, help boxes, etcetera.
    • logging out or logging in under a different name is a problem - browsers will keep sending authentication information to the site until you close the window
    • timeouts are difficult

    A very insightful article that tackles these point by point is here, but this results in a lot of browser-specific javascript hackery, workarounds for workarounds, et cetera. As such, it is also not forward-compatible so will require constant maintenance as new browsers are released. I do not consider that clean and clear design, plus I feel it is a lot of extra work and headache just so that I can enthusiastically show my REST-badge to my friends.

    I believe cookies are the solution. But wait, cookies are evil, aren't they? No, they're not, the way cookies are often used is evil. A cookie itself is just a piece of client-side information, just like the HTTP authentication info that the browser would keep track of while you browse. And this piece of client-side information is sent to the server at every request, again just like the HTTP Authentication info would be. Conceptually, the only difference is that the content of this piece of client-side state can be determined by the server as part of its response.

    By making sessions a RESTful resource with just the following rules:

    • A session maps a key to a user id (and possibly a last-action-timestamp for timeouts)
    • If a session exists, then that means that the key is valid.
    • Login means POSTing to /sessions, a new key is set as a cookie
    • Logout means DELETEing /sessions/{key} (with the overloaded POST, remember, we're a browser, and HTML 5 is a long way to go yet)
    • Authentication is done by sending the key as a cookie at every request and checking whether the session exists and is valid

    The only difference to HTTP Authentication, now, is that the authentication key is generated by the server and sent to the client who keeps sending it back, instead of the client computing it from the entered credentials.

    converter42 adds that when using https (which we should), it is important that the cookie will have its secure flag set so that authentication info is never sent over a non-secure connection. Great point, hadn't seen it myself.

    I feel that this is a sufficient solution that works fine, but I must admit that I'm not enough of a security expert to identify potential holes in this scheme - all I know is that hundreds of non-RESTful web applications use essentially the same login protocol ($_SESSION in PHP, HttpSession in Java EE, etc.). The cookie header contents are simply used to address a server-side resource, just like an accept-language might be used to access translation resources, etcetera. I feel that it is the same, but maybe others don't? What do you think, guys?

    0 讨论(0)
  • 2020-11-21 23:26

    First and foremost, a RESTful web service is STATELESS (or in other words, SESSIONLESS). Therefore, a RESTful service does not have and should not have a concept of session or cookies involved. The way to do authentication or authorization in the RESTful service is by using the HTTP Authorization header as defined in the RFC 2616 HTTP specifications. Every single request should contain the HTTP Authorization header, and the request should be sent over an HTTPs (SSL) connection. This is the correct way to do authentication and to verify the authorization of requests in a HTTP RESTful web services. I have implemented a RESTful web service for the Cisco PRIME Performance Manager application at Cisco Systems. And as part of that web service, I have implemented authentication/authorization as well.

    0 讨论(0)
  • 2020-11-21 23:28

    Enough already is said on this topic by good folks here. But here is my 2 cents.

    There are 2 modes of interaction:

    1. human-to-machine (HTM)
    2. machine-to-machine (MTM)

    The machine is the common denominator, expressed as the REST APIs, and the actors/clients being either the humans or the machines.

    Now, in a truly RESTful architecture, the concept of statelessness implies that all relevant application states (meaning the client side states) must be supplied with each and every request. By relevant, it is meant that whatever is required by the REST API to process the request and serve an appropriate response.

    When we consider this in the context of human-to-machine applications, "browser-based" as Skrebbel points out above, this means that the (web) application running in the browser will need to send its state and relevant information with each request it makes to the back end REST APIs.

    Consider this: You have a data/information platform exposed asset of REST APIs. Perhaps you have a self-service BI platform that handles all the data cubes. But you want your (human) customers to access this via (1) web app, (2) mobile app, and (3) some 3rd party application. In the end, even chain of MTMs leads up to HTM - right. So human users remain at the apex of information chain.

    In the first 2 cases, you have a case for human-to-machine interaction, the information being actually consumed by a human user. In the last case, you have a machine program consuming the REST APIs.

    The concept of authentication applies across the board. How will you design this so that your REST APIs are accessed in a uniform, secured manner? The way I see this, there are 2 ways:

    Way-1:

    1. There is no login, to begin with. Every request performs the login
    2. The client sends its identifying parameters + the request specific parameters with each request
    3. The REST API takes them, turns around, pings the user store (whatever that is) and confirms the auth
    4. If the auth is established, services the request; otherwise, denies with appropriate HTTP status code
    5. Repeat the above for every request across all the REST APIs in your catalog

    Way-2:

    1. The client begins with an auth request
    2. A login REST API will handle all such requests
    3. It takes in auth parameters (API key, uid/pwd or whatever you choose) and verifies auth against the user store (LDAP, AD, or MySQL DB etc.)
    4. If verified, creates an auth token and hands it back to the client/caller
    5. The caller then sends this auth token + request specific params with every subsequent request to other business REST APIs, until logged out or until the lease expires

    Clearly, in Way-2, the REST APIs will need a way to recognize and trust the token as valid. The Login API performed the auth verification, and therefore that "valet key" needs to be trusted by other REST APIs in your catalog.

    This, of course, means that the auth key/token will need to be stored and shared among the REST APIs. This shared, trusted token repository can be local/federated whatever, allowing REST APIs from other organizations to trust each other.

    But I digress.

    The point is, a "state" (about the client's authenticated status) needs to be maintained and shared so that all REST APIs can create a circle of trust. If we do not do this, which is the Way-1, we must accept that an act of authentication must be performed for any/all requests coming in.

    Performing authentication is a resource-intensive process. Imagine executing SQL queries, for every incoming request, against your user store to check for uid/pwd match. Or, to encrypt and perform hash matches (the AWS style). And architecturally, every REST API will need to perform this, I suspect, using a common back-end login service. Because, if you don't, then you litter the auth code everywhere. A big mess.

    So more the layers, more latency.

    Now, take Way-1 and apply to HTM. Does your (human) user really care if you have to send uid/pwd/hash or whatever with every request? No, as long as you don't bother her by throwing the auth/login page every second. Good luck having customers if you do. So, what you will do is to store the login information somewhere on the client side, in the browser, right at the beginning, and send it with every request made. For the (human) user, she has already logged in, and a "session" is available. But in reality, she is authenticated on every request.

    Same with Way-2. Your (human) user will never notice. So no harm was done.

    What if we apply Way-1 to MTM? In this case, since its a machine, we can bore the hell out of this guy by asking it submit authentication information with every request. Nobody cares! Performing Way-2 on MTM will not evoke any special reaction; its a damn machine. It could care less!

    So really, the question is what suits your need. Statelessness has a price to pay. Pay the price and move on. If you want to be a purist, then pay the price for that too, and move on.

    In the end, philosophies do not matter. What really matters is information discovery, presentation, and the consumption experience. If people love your APIs, you did your job.

    0 讨论(0)
  • 2020-11-21 23:29

    Using a Public key infrastruction in which the registration of a key involves proper binding ensures that the public key is bound to the individual to which it is assigned in a way that ensures non-repudiation

    See http://en.wikipedia.org/wiki/Public_key_infrastructure . If you follow the proper PKI standards, the person or agent who improperly uses the stolen key can be identified and locked out. If the agent is required to use a certificate, the binding gets pretty tight. A clever and quick-moving thief can escape, but they leave more crumbs.

    0 讨论(0)
  • 2020-11-21 23:30

    Update on 16-Feb-2019

    The approach mentioned earlier below is essentially "Resource Owner Password Credential" grant type of OAuth2.0. This is an easy way to get up and running. However, with this approach every application in the organization will end up with its own authentication and authorization mechanisms. The recommended approach is "Authorization Code" grant type. Additionally, in my earlier answer below I recommended browser localStorage for storing auth tokens. However, I've come to believe that cookie is the right option for this purpose. I have detailed my reasons, authorization code grant type implementation approach, security considerations etc. in this StackOverflow answer.


    I think the following approach can be used for REST service authentication:

    1. Create a login RESTful API to accept username and password for authentication. Use HTTP POST method to prevent caching and SSL for security during transit On successful authentication, the API returns two JWTs - one access token (shorter validity, say 30 minutes) and one refresh token (longer validity, say 24 hours)
    2. The client (a web based UI) stores the JWTs in local storage and in every subsequent API call passes the access token in "Authorization: Bearer #access token" header
    3. The API checks the validity of the token by verifying the signature and expiry date. If the token is valid, check if the user (It interprets the "sub" claim in JWT as username) has access to the API with a cache lookup. If the user is authorized to access the API, execute the business logic
    4. If the token is expired, the API returns HTTP response code 400
    5. The client, on receiving 400/401, invokes another REST API with the refresh token in "Authorization: Bearer #refresh token" header to get a new access token.
    6. On receiving the call with refresh token, check if the refresh token is valid by checking the signature and the expiry date. If the refresh token is valid, refresh the access right cache of the user from DB and return new access token and refresh token. If the refresh token is invalid, return HTTP response code 400
    7. If a new access token and refresh token are returned, go to step 2. If HTTP response code 400 is returned, the client assumes that the refresh token has expired and asks for username and password from the user
    8. For logout, purge the local storage

    With this approach we are doing the expensive operation of loading the cache with user specific access right details every 30 minutes. So if an access is revoked or new access is granted, it takes 30 minutes to reflect or a logout followed by a login.

    0 讨论(0)
  • 2020-11-21 23:32

    How to handle authentication in a RESTful Client-Server architecture is a matter of debate.

    Commonly, it can be achieved, in the SOA over HTTP world via:

    • HTTP basic auth over HTTPS;
    • Cookies and session management;
    • Token in HTTP headers (e.g. OAuth 2.0 + JWT);
    • Query Authentication with additional signature parameters.

    You'll have to adapt, or even better mix those techniques, to match your software architecture at best.

    Each authentication scheme has its own PROs and CONs, depending on the purpose of your security policy and software architecture.

    HTTP basic auth over HTTPS

    This first solution, based on the standard HTTPS protocol, is used by most web services.

    GET /spec.html HTTP/1.1
    Host: www.example.org
    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    

    It's easy to implement, available by default on all browsers, but has some known drawbacks, like the awful authentication window displayed on the Browser, which will persist (there is no LogOut-like feature here), some server-side additional CPU consumption, and the fact that the user-name and password are transmitted (over HTTPS) into the Server (it should be more secure to let the password stay only on the client side, during keyboard entry, and be stored as secure hash on the Server).

    We may use Digest Authentication, but it requires also HTTPS, since it is vulnerable to MiM or Replay attacks, and is specific to HTTP.

    Session via Cookies

    To be honest, a session managed on the Server is not truly Stateless.

    One possibility could be to maintain all data within the cookie content. And, by design, the cookie is handled on the Server side (Client, in fact, does even not try to interpret this cookie data: it just hands it back to the server on each successive request). But this cookie data is application state data, so the client should manage it, not the server, in a pure Stateless world.

    GET /spec.html HTTP/1.1
    Host: www.example.org
    Cookie: theme=light; sessionToken=abc123
    

    The cookie technique itself is HTTP-linked, so it's not truly RESTful, which should be protocol-independent, IMHO. It is vulnerable to MiM or Replay attacks.

    Granted via Token (OAuth2)

    An alternative is to put a token within the HTTP headers so that the request is authenticated. This is what OAuth 2.0 does, for instance. See the RFC 6749:

     GET /resource/1 HTTP/1.1
     Host: example.com
     Authorization: Bearer mF_9.B5f-4.1JqM
    

    In short, this is very similar to a cookie and suffers to the same issues: not stateless, relying on HTTP transmission details, and subject to a lot of security weaknesses - including MiM and Replay - so is to be used only over HTTPS. Typically, a JWT is used as a token.

    Query Authentication

    Query Authentication consists in signing each RESTful request via some additional parameters on the URI. See this reference article.

    It was defined as such in this article:

    All REST queries must be authenticated by signing the query parameters sorted in lower-case, alphabetical order using the private credential as the signing token. Signing should occur before URL encoding the query string.

    This technique is perhaps the more compatible with a Stateless architecture, and can also be implemented with a light session management (using in-memory sessions instead of DB persistence).

    For instance, here is a generic URI sample from the link above:

    GET /object?apiKey=Qwerty2010
    

    should be transmitted as such:

    GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789
    

    The string being signed is /object?apikey=Qwerty2010&timestamp=1261496500 and the signature is the SHA256 hash of that string using the private component of the API key.

    Server-side data caching can be always available. For instance, in our framework, we cache the responses at the SQL level, not at the URI level. So adding this extra parameter doesn't break the cache mechanism.

    See this article for some details about RESTful authentication in our client-server ORM/SOA/MVC framework, based on JSON and REST. Since we allow communication not only over HTTP/1.1, but also named pipes or GDI messages (locally), we tried to implement a truly RESTful authentication pattern, and not rely on HTTP specificity (like header or cookies).

    Later Note: adding a signature in the URI can be seen as bad practice (since for instance it will appear in the http server logs) so it has to be mitigated, e.g. by a proper TTL to avoid replays. But if your http logs are compromised, you will certainly have bigger security problems.

    In practice, the upcoming MAC Tokens Authentication for OAuth 2.0 may be a huge improvement in respect to the "Granted by Token" current scheme. But this is still a work in progress and is tied to HTTP transmission.

    Conclusion

    It's worth concluding that REST is not only HTTP-based, even if, in practice, it's also mostly implemented over HTTP. REST can use other communication layers. So a RESTful authentication is not just a synonym of HTTP authentication, whatever Google answers. It should even not use the HTTP mechanism at all but shall be abstracted from the communication layer. And if you use HTTP communication, thanks to the Let's Encrypt initiative there is no reason not to use proper HTTPS, which is required in addition to any authentication scheme.

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