I'm building Pylons-based web application with RESTful API, which currently lacks any authentication. So I'm going to implement that and in order to avoid all the trouble and caution with storing user passwords, I'd like to use OpenID for authentication. What would be the best way to do this? Are these two things compatible? Are there existing REST APIs that use OpenID that I can take inspiration from?
I've now spent some time researching the options and would like to summarize the findings.
First, a little bit more context -- I develop and control both the service and API consumer. Consumer is Flash-based app that is served from the same host the API is now and is supposed to be used in browser. No third party clients in sight yet.
So the question can be divided in two parts,
how do I do the OpenID authentication via API
how do I maintain the "authenticated" state in subsequent requests
For first part, OpenID authentication almost always includes interactive steps. During the authentication process there will most likely be a step where user is in OpenID provider's web page, signing in and pressing some "I agree" button. So API cannot and shouldn't handle this transparently (no "tell me your OpenID provider and password and I'll do the rest"). Best it can do is pass forth and back HTTP links that client has to open and follow instructions.
Maintaining "authenticated" state
REST APIs should be stateless, each request should include all the information needed to handle it, right? It wouldn't make any sense to authenticate against OpenID provider for each request, so some kind of session is neccessary. Some of the options for communicating session key (or "access token" or username/password) are:
HTTPS + BASIC authentication ("Authorization: Basic ..." header in each request)
Signing requests Amazon-style ("Authorization: AWS ... " header in each request)
OAuth: acquire Access Token, include that and a bunch of other parameters in each request
Cookie that stores session key ("Cookie: ... " header in each request)
Signed cookie that stores session information in the cookie itself
There's just one API consumer right now, so I chose to go for simplest thing that could possibly work -- cookies. They are super-easy to use in Pylons, with help of Beaker. They also "just work" in the Flash app -- since it runs inside browser, browser will include relevant cookies in the requests that Flash app makes -- the app doesn't need to be changed at all with respect to that. Here's one StackOverflow question that also advocates using cookies: RESTful authentication for web applications
Beaker also has nice feature of cookie-only sessions where all session data is contained in the cookie itself. I guess this is about as stateless as it gets. There is no session store on server. Cookies are signed and optionally encrypted to avoid tampering with them in client side. The drawback is that cookie gets a bit bigger, since it now needs to store more than just session key. By removing some stuff I didn't really need in the session (leftovers from OpenID authentication) I got the cookie size down to about 200 bytes.
OAuth is a better fit for API usage. Here's an example of OAuth in use in Python: oauth-python-twitter. Leah Culver's python-oauth library is the canonical implementation of OAuth in Python, but python-oauth2 is a recent contender that is getting some buzz. As for inspiration, django-piston has support for using OAuth to do auth when creating RESTful APIs for Django, though the documentation isn't as nice as I'd like for that particular topic.
If you build API, you could check OAuth protocol. It's complementary to OpenID.
Related
All of the React Native Twitter Login Clients that I'm finding seem to be hard-coding the TWITTER_CONSUMER_KEY and TWITTER_CONSUMER_SECRET into the the client code, rather than relying on a server to generate tokens and/or a twitter redirect URL.
Is this safe? (e.g. couldn't a consumer then DOS the API with the TWITTER_CONSUMER_KEY, causing the app to be rate limited?)
Is this the correct way to do it?
Is there a better / more secure way?
According to twitter's documentation, it seems like this is NOT the correct way to do this:
"In the event that you believe that your API keys has been exposed, you should regenerate your API keys by following these steps" - Authentication best practices
Examples which specify that the consumer key/secret should be hardcoded:
https://rnfirebase.io/docs/v5.x.x/auth/social-auth#Twitter
https://github.com/GoldenOwlAsia/react-native-twitter-signin/blob/master/Example/TwitterButton.js#L14
Related questions:
Twitter consumer secret really a secret?
Is it a security vulnerability
Yes.
Your app can be rate limited or flagged as malware/spam etc.
Is there a better / more secure way?
Basically only to have your own site auth (oauth2) done correctly and proxy specific requests from your clients, after validation or a simplified locked down site API that is then translated to the Twitter API.
Why is this, Twitter app-only auth supports OAuth2, allows a secure negotiated handshake and then requests made using a Bearer token. In this mode you can make requests on behalf of your App, but without a logged in user. So can't post tweets or see private accounts or read DMs.
For user-auth, Twitter only support OAuth1 and both the App and User are authenticated, but using a model that assumed plaintext http, so can't share a single token. Every single request needs to be made using consumer key/secret and signing the request. So there isn't a way to do this from a javascript client safely.
Is this safe?
Absolutely not. A bad actor can get users to authenticate via Twitter to receive their token credentials and then use your app's consumer key/secret (which would be available in plain text) to masquerade as your app to do all kinds of nasty stuff.
Is this the correct way to do it?
Given the security vulnerability described above, no.
Is there a better / more secure way?
I'm currently in the process of trying to figure out how to securely achieve authentication with Twitter. This involved a lot of reading, but it appears as though it's simply not possible without your own backend. I'll try and explain why:
Your goal is to receive the user's email/Twitter-ID
To achieve (1), you need to send a request to the GET account/verify_credentials endpoint (https://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials).
To do (2), you need to provide an authorisation header, which is constructed out of several items, including the user's OAuth tokens as well as your app's consumer key/secret. More info here: https://developer.twitter.com/en/docs/authentication/oauth-1-0a/authorizing-a-request.
You retrieve the user's OAuth tokens using the 3-legged OAuth flow
described here: https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens. The first step of this process is to send a POST request to the oauth/request_token endpoint (https://developer.twitter.com/en/docs/authentication/api-reference/request_token).
This endpoint itself requires an authorisation header constructed using
your app's consumer key/secret.
Obviously you can't perform step (4) because that implies you would have your consumer secret available in the client; even if it's not hardcoded, it would have to be in memory at runtime, at some point
Once you have your own backend service, one option would be for your client app to open a browser and direct to an endpoint (let's call it /auth/twitter) on this service which will perform all the steps mentioned above.
This same service could also implement another endpoint (/auth/twitter/token) which handles requests to the callback URL, which you set in your Twitter app settings. This callback URL is used as part of the same 3-legged flow. This endpoint would have all the information needed to then go ahead and retrieve the user's email/Twitter-ID.
Finally, /auth/twitter/token can redirect to a custom URL which your client app would need to handle as part of its URL schemes. It can include enough information by way of parameters for your app to continue as needed post-auth.
I am developing a asp.net mvc project with Web API. Web API will be consumed by Website, mobile apps and third party. Now, on some APIs will be called on Home page only without any login and same APIs will be called after login only.
Now, considering my website scenario, I have called APIs from AngularJs. We called an api which will generate a token on session_start. Then from NG we called a mvc controller method which will simply get that token and then the token will passed in HTTP-Header in All requests.
On API side, we fetch the token, decrypt it and show result.
Problem is, when I see Google Chrome's Network Tab (press F12) I can easily see API Calls and even Token in headers. I feel security vulnerability. For Open APIs, we thought of having some expiry time and request counts. But some APIs will be sensitive, like adding data in DB(POST APIs, based on data passed as parameters) and they also will be available to Guest Users. We don't want someone to misuse it and do harmful things.
How can we achieve maximum security in this scenario? What will be ideal security process?
To further explain Marco Sandrini's comment...
The security does not rely on hiding the API structure (method names, data format, etc...), but on giving access to those APIs only to authorized clients, which is what your tokens should do. In other words if your tokens are cryptographically sound (cannot be spoofed or faked), your connection is protected (nobody can intercept your tokens) and your backend correctly authenticates and authorizes your clients, you should be fine.
The token should not be subject to replay attacks. The server should already be expecting a different permutation of the token for subsequent requests, and you shouldn't know how to produce that by reading the token.
Proper SSL/TLS will protect the content of the connection from prying eyes. If your guest users can see other's sensitive information in their Chrome network tab, then you should worry because something has gone wrong with your implementation strategy.
Goal: My server needs to direct non-users to a landing/home page, and logged in users to the actual app. When the app is loaded, it will make authenticated HTTP requests to a RESTful API (via Ajax).
I have a RESTful API that needs authentication. On another server I have my website, which also needs authentication, so I can determine whether to display the landing/home page for non-users or the app for logged in users.
Initially I thought it would be enough to implement HTTP Basic Auth for the RESTful API. However, in order to get authentication running for my website too, I would also need to setup authentication there, which would mean duplicating the low-level code to check the credentials in the database in both the REST API and the website servers.
Alternatively, I wondered if the website could authenticate via the RESTful API. For example, in my request handler for POST /login, I could make a GET request to my API, passing along the user credentials from the request body. If the request returns 200 OK, I could sign the user’s session, thus authenticating them. From there onwards, the Ajax requests to the REST API need to be authenticated with the same credentials, so I could:
set a cookie containing the credentials, thus allowing the JavaScript to retrieve the credentials before doing the request (OK with SSL?)
dump the credentials in the served HTML for the web app thus allowing the JavaScript to retrieve the credentials before doing the request (OK with SSL?)
proxy the API through the web app server, where I could retrieve the credentials from the session and add them to the Authorization header of the proxied request?
Alternatively, I imagine I could just share a session between the two servers, although I’ve heard that’s bad practice for RESTful design.
What would be wrong with doing it like this? Is there a better way to meet my goal?
I recently implemented something similar to this (assuming I understand you correctly), and there seemed to be a few viable options.
Have the server side of your web-app always authenticate with a specific username/password when accessing the REST API, ensuring that your web-app is always trusted and assuming that users are properly logged in on the web-app if a request is authenticated as the app.
Pros: Easy to implement, easy to understand, easy to extend for other applications as well (we had a CLI that accessed the same REST API as well).
Cons: It's impossible for the REST API to know which user is actually accessing it. If a trusted client is compromised the whole system is compromised.
Have the server side of your web-app keep user details in the session and authenticate using the users credentials every time you access the REST API.
Pros: Fairly easy to implement (although some authentication mechanisms make it hard to keep hold of the user password - for good reason). The whole procedure is transparent to the REST API.
Cons: You're now storing (for all intents and purposes in clear-text) the username and password of a user in the session of the web-server - one of the most prime targets for attack in the system.
Create an authentication system on the REST API that authenticates a request with a username/password authorization and returns a token that is valid for a limited time.
Pros: More secure, if your web-app is compromised you're not providing the attacker with your users username/passwords, but instead only allowing them a limited time access.
Cons: Much harder to implement. You might need to deal with token timeouts specifically. For purists it also means that your REST implementation (or at least the authentication system) will be arguably "stateful".
What you should implement would depend on your situation. Personally I'd definitely go with the more secure option (the last one), but due to external constraints we were forced to implement the first option in our specific case (with the promise we'd revisit it and upgrade later - unfortunately later never comes).
I think your approach with using Basic HTTP Authentication in REST service and having your app authenticate with the service is perfectly fine. The only caveat here (which I am sure you are aware of), is that your REST service should run over SSL, as Basic HTTP authentication is not very secure - username and password are just Base64 encoded.
I want to make a web application that's a Single-Page client that interacts with a REST API in the server. I need to authenticate users of my app as opposed to authenticate third party-apps (the latter being the focus of most tradional REST bibliography).
After googling a lot, I found there are many options (Basic HTTP Auth, HTTP digest, OAuth, etc) and several desirable properties one might get depending on the one chosen. For example, Basic Auth is simple but sends plain passwords unencrypted, which is not a good idea unless you guarantee that your app will run under TLS. Digest on the contrary doesn't send the credentials on every request, but prevents strong password encryption and is vulnerable to man in the middle attacks[1]. Meteor introduced SRP which avoids storing and sending passwords[2].
It appears to me that the consensus is to use OAuth, particulary the OAuth2 credentials flow, since I want to authorize access to my resources on my own server[3][4][5]. What I don't get is what are the benefits of this particular approach. I do get the benefits of using OAuth as a form of delegate authentication, much like those of using OpenID for federated authentication: you don't handle authentication data at all in your server. But in the case you apply the credentials flow for authorization (or OAuth1 2-legged flow for that matter), not introducing a third party, it looks like you still have to handle authentication by some other means, like HTTP basic or digest. So if you're doing that why not stick to that only method, and send the credentials on every request, instead of the token?
It's just to reduce the amount of requests where you have to actually send the credentials? It's just to stick to the OAuth convention? Those don't sound like strong arguments over the other methods. So, I'm I missing some other aspects or did I misunderstood something?
If you are not federating, there is not really a good case for using OAuth.
If you just want to authenticate to your own service, basic or forms authentication is the way to go. The catch, as you've pointed out, is that you must use HTTPS. However, that applies to all authentication methods.
As long as you're using HTTPS, you can leave protection of credentials while in transit to the transport level security. That's what it's there for and (for the most part) that's what it's good at. If you're using plain HTTP (anywhere in your application, not just for authentication), you're done. There are all manner of very clever MitM attacks that totally break the security of any system that employs HTTP anywhere (Moxie Marlinspike gave an interesting presentation on the subject at Black Hat back in 2009).
I'm developing a REST API that requires authentication. Because the authentication itself occurs via an external webservice over HTTP, I reasoned that we would dispense tokens to avoid repeatedly calling the authentication service. Which brings me neatly to my first question:
Is this really any better than just requiring clients to use HTTP Basic Auth on each request and caching calls to the authentication service server-side?
The Basic Auth solution has the advantage of not requiring a full round-trip to the server before requests for content can begin. Tokens can potentially be more flexible in scope (i.e. only grant rights to particular resources or actions), but that seems more appropriate to the OAuth context than my simpler use case.
Currently tokens are acquired like this:
curl -X POST localhost/token --data "api_key=81169d80...
&verifier=2f5ae51a...
×tamp=1234567
&user=foo
&pass=bar"
The api_key, timestamp and verifier are required by all requests. The "verifier" is returned by:
sha1(timestamp + api_key + shared_secret)
My intention is to only allow calls from known parties, and to prevent calls from being reused verbatim.
Is this good enough? Underkill? Overkill?
With a token in hand, clients can acquire resources:
curl localhost/posts?api_key=81169d80...
&verifier=81169d80...
&token=9fUyas64...
×tamp=1234567
For the simplest call possible, this seems kind of horribly verbose. Considering the shared_secret will wind up being embedded in (at minimum) an iOS application, from which I would assume it can be extracted, is this even offering anything beyond a false sense of security?
Let me seperate up everything and solve approach each problem in isolation:
Authentication
For authentication, baseauth has the advantage that it is a mature solution on the protocol level. This means a lot of "might crop up later" problems are already solved for you. For example, with BaseAuth, user agents know the password is a password so they don't cache it.
Auth server load
If you dispense a token to the user instead of caching the authentication on your server, you are still doing the same thing: Caching authentication information. The only difference is that you are turning the responsibility for the caching to the user. This seems like unnecessary labor for the user with no gains, so I recommend to handle this transparently on your server as you suggested.
Transmission Security
If can use an SSL connection, that's all there is to it, the connection is secure*. To prevent accidental multiple execution, you can filter multiple urls or ask users to include a random component ("nonce") in the URL.
url = username:key#myhost.com/api/call/nonce
If that is not possible, and the transmitted information is not secret, I recommend securing the request with a hash, as you suggested in the token approach. Since the hash provides the security, you could instruct your users to provide the hash as the baseauth password. For improved robustness, I recommend using a random string instead of the timestamp as a "nonce" to prevent replay attacks (two legit requests could be made during the same second). Instead of providing seperate "shared secret" and "api key" fields, you can simply use the api key as shared secret, and then use a salt that doesn't change to prevent rainbow table attacks. The username field seems like a good place to put the nonce too, since it is part of the auth. So now you have a clean call like this:
nonce = generate_secure_password(length: 16);
one_time_key = nonce + '-' + sha1(nonce+salt+shared_key);
url = username:one_time_key#myhost.com/api/call
It is true that this is a bit laborious. This is because you aren't using a protocol level solution (like SSL). So it might be a good idea to provide some kind of SDK to users so at least they don't have to go through it themselves. If you need to do it this way, I find the security level appropriate (just-right-kill).
Secure secret storage
It depends who you are trying to thwart. If you are preventing people with access to the user's phone from using your REST service in the user's name, then it would be a good idea to find some kind of keyring API on the target OS and have the SDK (or the implementor) store the key there. If that's not possible, you can at least make it a bit harder to get the secret by encrypting it, and storing the encrypted data and the encryption key in seperate places.
If you are trying to keep other software vendors from getting your API key to prevent the development of alternate clients, only the encrypt-and-store-seperately approach almost works. This is whitebox crypto, and to date, no one has come up with a truly secure solution to problems of this class. The least you can do is still issue a single key for each user so you can ban abused keys.
(*) EDIT: SSL connections should no longer be considered secure without taking additional steps to verify them.
A pure RESTful API should use the underlying protocol standard features:
For HTTP, the RESTful API should comply with existing HTTP standard headers. Adding a new HTTP header violates the REST principles. Do not re-invent the wheel, use all the standard features in HTTP/1.1 standards - including status response codes, headers, and so on. RESTFul web services should leverage and rely upon the HTTP standards.
RESTful services MUST be STATELESS. Any tricks, such as token based authentication that attempts to remember the state of previous REST requests on the server violates the REST principles. Again, this is a MUST; that is, if you web server saves any request/response context related information on the server in attempt to establish any sort of session on the server, then your web service is NOT Stateless. And if it is NOT stateless it is NOT RESTFul.
Bottom-line: For authentication/authorization purposes you should use HTTP standard authorization header. That is, you should add the HTTP authorization / authentication header in each subsequent request that needs to be authenticated. The REST API should follow the HTTP Authentication Scheme standards.The specifics of how this header should be formatted are defined in the RFC 2616 HTTP 1.1 standards – section 14.8 Authorization of RFC 2616, and in the RFC 2617 HTTP Authentication: Basic and Digest Access Authentication.
I have developed a RESTful service for the Cisco Prime Performance Manager application. Search Google for the REST API document that I wrote for that application for more details about RESTFul API compliance here. In that implementation, I have chosen to use HTTP "Basic" Authorization scheme. - check out version 1.5 or above of that REST API document, and search for authorization in the document.
In the web a stateful protocol is based on having a temporary token that is exchanged between a browser and a server (via cookie header or URI rewriting) on every request. That token is usually created on the server end, and it is a piece of opaque data that has a certain time-to-live, and it has the sole purpose of identifying a specific web user agent. That is, the token is temporary, and becomes a STATE that the web server has to maintain on behalf of a client user agent during the duration of that conversation. Therefore, the communication using a token in this way is STATEFUL. And if the conversation between client and server is STATEFUL it is not RESTful.
The username/password (sent on the Authorization header) is usually persisted on the database with the intent of identifying a user. Sometimes the user could mean another application; however, the username/password is NEVER intended to identify a specific web client user agent. The conversation between a web agent and server based on using the username/password in the Authorization header (following the HTTP Basic Authorization) is STATELESS because the web server front-end is not creating or maintaining any STATE information whatsoever on behalf of a specific web client user agent. And based on my understanding of REST, the protocol states clearly that the conversation between clients and server should be STATELESS. Therefore, if we want to have a true RESTful service we should use username/password (Refer to RFC mentioned in my previous post) in the Authorization header for every single call, NOT a sension kind of token (e.g. Session tokens created in web servers, OAuth tokens created in authorization servers, and so on).
I understand that several called REST providers are using tokens like OAuth1 or OAuth2 accept-tokens to be be passed as "Authorization: Bearer " in HTTP headers. However, it appears to me that using those tokens for RESTful services would violate the true STATELESS meaning that REST embraces; because those tokens are temporary piece of data created/maintained on the server side to identify a specific web client user agent for the valid duration of a that web client/server conversation. Therefore, any service that is using those OAuth1/2 tokens should not be called REST if we want to stick to the TRUE meaning of a STATELESS protocol.
Rubens