How to implement API security for local and remote requests? - web-services

I have setup an web-based API to allow a remote app to GET/POST data. Every API call is authenticated with a User ID and Password that is encrypted with a secret key known only to the remote app and the website. This authentication not only ensures that the user can access the API, but also allows me to implement security features based on the user's profile (i.e. User A can see items A & B, but not item C).
I would like my server-side website pages to be able to call the same API methods remotely via AJAX calls, but, something just doesn't seem right about storing encrypted passwords in the code, and, my website implements a "Login As" feature, which will not allow me to set the encrypted password, since the passwords are not stored in plain text.
What is a good way to implement API security for both remote and "local" calls that doesn't require encrypting the user's password?

You should not be storing usernames and passwords in server side code. Sooner or later someone will lay eyes on your code and your data will be vulnerable.
But you should also not be storing secrets (key) in client side code. You should not assume your client can be trusted to keep that secret.
Giving user A access to item A and B, but not C is called authorization and depends on you knowing who calls your API (authentication).
You should probably look into a authentication protocol like OpenID Connect and an authorization protocol like OAuth 2.0.
Also see my answer to this question.

Related

Tronweb authentication

I want to build a webapp that uses the wallet address as account, but yet I want to store the user in my db to allow specifying a nickname.
The problem I'm dealing with is that I want to call different apis, where the user needs to be authenticated / authorized in order to gain access .
Since the authentication happens 100% client side in my case (through the tronlink extension and TronWeb), I don't see another way as to add supplementary authentication for my webapp specifically.
If the user logs in to my app with a different password (not using the private key of the wallet), it seems like bad user experience as the user needs to authenticate twice (through Tronweb AND my webapp with a password).
How do you solve this problem?
It seems that the way to handle this is to foresee a separate login flow for the web app after all.
Even when the user already has logged in into Tronlink, it needs to obtain a token to authenticate rest calls.
The way it would appear to work is by generating a random nonce and storing this nonce along with the public key in the User table.
The login flow then consists of signing the nonce in the front-end, and verifying the signature in the backend after which the token will be generated and returned.

How can I implement user authentication for ColdFusion Web Services called from a mobile application?

I am developing several Web Services that will be accessed by a mobile application. I have several requirements:
Each user will need to sign in with their own User ID and Password (the same User ID and Password they use to sign into the website).
Every Web Service request will need to be authenticated to ensure that the request is coming from the mobile app(s).
Every Web Service request will need to authenticate the user, since there is user-specific fucntionality built in, and access will need to be blocked if the user's account is disabled.
Let's assume that OAuth is not an option.
In order to ensure that Web Service requests are coming only from the mobile app(s), I am planning to use HTTP Basic Authentication in IIS (the mobile app(s) will need to have a User Account setup in Windows Server and the mobile app will need to store the User Name & Password and pass these in the header).
Next is the User Authentication for each Web Service request. Would it be suitable to encrypt the User ID, Password, and some shared secret key (a "pepper", of sort) with AES-256, pass that encrypted string as a parameter with each request (over HTTPS, of course), and then decrypt and parse it on the server to authenticate? This is the existing plan, but something just doesnt seem right about it - like it's not "secure enough".
What else can I do to properly authenticate users for Web Service requests?
I recently went through this problem and asked opinions from a group of senior people about how they solve the problem. Opinions were varied, but one consistent feeling is that your level of security depends on the use case of your application. Are you doing online banking or storing medical records? Then your security needs may be quite high. Social networking? Maybe not so much.
Basic Authentication is generally fine when encrypted over SSL, ColdFusion works well with it. If you use Basic Auth, make sure to encrypt your traffic with 1024-bit keys or better. Don't authenticate every request with username/password - that's unnecessary. Authenticate the first request, set a session token, and rely on the session token for your identification of users.
Set a polling mechanism from the client to the server to keep the session alive - set the session timeout to 30 minutes and the polling frequency at 25 minutes, for example. Otherwise you may need to re-authenticate expired sessions. Again, how you approach this part of the solution depends on your paranoia level, which depends on what kind of data/app you are dealing with.
Cookies, and therefore sessions, should work fine in iOS apps. If you use sessions to verify identity after authentication, make sure your session cookies are memory-only (set at the server level).
Check the SSL implementation of your server against the Qualysis SSL Test:
https://www.ssllabs.com/ssltest/
The report will give you a surprising amount of detail about the strength of your SSL implementation.
Lastly, consider implementing two-factor authentication to combat password theft.
If you ignore the SSL advice and plan on encrypting your password and communicating over an insecure channel, look at the Kerberos protocol for a well-known example of how to authenticate securely:
http://en.wikipedia.org/wiki/Kerberos_%28protocol%29
Yes, you can use Basic Authentication but that means the client will need to store the username/password in plain text, and also send them over in plain text. Sending part is sort of fine if it's under HTTPS, but storing username/password in plain text may not be a good idea, unless you're using some secure key store.
Let's assume you have decided that Basic Authentication is the way to go, and you want to make use of the official CF way of supporting that, then you can use CFLOGIN.name & CFLOGIN.password. You may also check out Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion. In the remote cfc side, always validate the username/password, or return some sort of token and asks the client to use that token going forward. The token can be cfid+cftoken if you like, or even roll your own that never expires. If you use cfid+cftoken, and send them over as cookie or in body along with your web service call, I believe you can resume the session if you so choose.

End user authentication for RESTful web services

I have an internal-facing RESTful web service. There are various client applications using the service, and the client apps themselves have end users. The web service needs to authorize requests based on the end user identities.
The question: What are the typical options for authenticating the end user here? That is, I want to authenticate the user, not the client application. (I don't mind if authenticating the client application is part of the scheme, but ultimately I need to know that the end user is who I think he or she is.)
One possible scheme, for example, would be to have per-client system accounts, and then have the client simply assert the user's identity (e.g. in an HTTP request header, say). So we authenticate the client application and delegate user authentication to the client. I don't think this is a very strong scheme, though, because it depends too much on keeping the system account credentials secret. I have seen too many examples of people e-mailing system account credentials around to put much faith in this sort of approach.
Another approach might be to have the client app, upon user login, use the user's credentials to get a token from the API, and then use that token for subsequent API requests. That way the authentication is user-specific without requiring the client app to hang onto the username/password credentials.
Anyway I'd like to have a better sense for the range of options I should be considering here.
The problem that you describe with "delegated authentication" is a real one. It means that a "client application" using it's credentials has access to the whole breadth of user data. This access can be used maliciously (for example a "semi-trusted" app harvesting api data) or negligently (for example an app accidentally exposing a Direct Object Reference Vulnerability - https://www.owasp.org/index.php/Top_10_2010-A4-Insecure_Direct_Object_References)
Probably the most prevalent "token based" scheme is OAuth2 (http://oauth.net/2/), and the precursor, OAuth, which many sites choose to continue to use.
OAuth2 has a number of roles:
resource owner (the user in your case)
resource server (your api)
client (the apps you talk about)
authorization server (not clear who or what would fulfil this role in your case)
The basic scheme is that the resource owner authenticates using their credentials directly with the authorization server. They are then asked if they want to grant some information (which may just be a persistent identifier, or a description of the information exposed by your api) to some client. When they accept an 'auth code' is sent to the client and they use that (combined with their own credentials) to receive an 'access token'. This access token can then be used to authenticate against the resource server (which can check it's authenticity back against the authorization server).
Normally the way this is used is that the authorization server and the resource server are owned and managed by the same entity (for example google and facebook would fulfil this role) and then clients are independently managed.
The scheme can also be used internally within an organisation without the "explicit grant" which can still at least confirm that a specific end-user is present before releasing any data from an api.

OAuth 2.0 client ids in Django/tastypie implementation

I'm trying to implement OAuth 2.0 for my API. I'm using a third party library to act as the basic OAuth provider, django-oauth2-provider,
and Tastypie as the framework. Those details shouldn't matter too much. The OAuth 2.0 works -- when a user is created, an OAuth 2 client
that manages the user's secret_key and their id is created. A customer can then supply the user ID they get back from the user creation
endpoint along with their username and password to get an access token which allows them to use API endpoints.·
Where I run into issues is retrieving the client id (which must be passed into requests for the access token). Obviously when a user is first created
I can return the client_id with the HTTP response. After that, however, there will obviously be cases where the user doesn't have their client id·
stored locally (this is a traditional user/app setup, not something like Google APIs where your client id is always visible). I want to protect
GET requests to the customer resource with OAuth, but that means I can't query the API for a given user's client ID. And it seems like the whole point
of OAuth is defeated if I can always just pass in a username and password to retrieve my client id from some oauth endpoint. Am I thinking about this wrong?
Also, from reading the OAuth specs I'm under the impression that a client id and client secret are all that should be supplied for getting granted an access token. Yet the implementation I'm using defaults to forcing the user to supply a client id, client secret, username, and password. I've overridden the implementation to require only the client id and secret, but I want to make sure that was the right call and I'm not missing something.
Edit for flup's response:
I'm dealing with a Django API as the resource server, and a user of an iPhone app as the resource owner. The iPhone app is directly associated with the server -- in other words, there are no third parties involved here and no plans to involve them in the future; all software is ours. I would think that the password flow would be what I would need in that case. Indeed, that seems to be what django-oauth2-provider supplies by default. I'd like to stay somewhat in line with what they are doing to not have to completely reinvent the wheel.
The goal of oauth2 is to let the resource owner give a client a valet key which authorizes it to access certain resources on your server on his behalf.
If there are no third parties involved, there is no client to authorize and no need to use oauth2.
Instead, you could use the standard authentication mechanisms present in tastypie.

advantages of access keys in webservices

I just read about how access keys and secret ids could be used to send authenticated requests to a RESTful webservice. However, I dont understand the advantages of using it over other alternatives(such as sending over the username and password, for instance), assuming that all communication with the server is over HTTPS.
What are the advantages of using such a mechanism?
Thanks.
Access key is roughly equivalent to a username, and access secret is roughly equivalent to a password. The access key makes it possible for the service to figure out who you are, and the access secret affirms that it's really you ("you" being your site in this context). The access key is not sensitive, and it is usually okay to be published in frontend code (Javascript, links in HTML, etc), while the access secret you need to keep, well, secret, because otherwise other people/sites will be able to impersonate your requests to the service. There is not much difference between key/secret and username/password scheme; the main difference is that key and secret are usually randomly generated by the service, which prevents people from using values like "default/12345" and similar nonsense.