Here's the set-up:
I have a server-based application. So, all the data is on a server (call it server 'A') and users connect to that server using a desktop-based rich client. The rich client also allows the user to connect to some other server (call it 'X'), that is completely unrelated to server A.
Question:
The user has logged into server 'X' from the rich client, and so the rich client has the right cookie to authenticate against server X. Now, the user makes an invocation on server A, which requires server A to go out and get some data from server X. Is it possible to somehow circumvent having server A to authenticate against server X given that the rich client has already authenticated against server X. Is there some way to share the cookie (with server A acting as the second client)? Or some way to have server A forward server X's authentication request back to the rich client and having it resolve against the cookie in the rich client. BTW, we use apache's HttpClient.
I am not very knowledgeable about server interactions, but am trying to gauge how easy/hard or common/rare is it to do something like this. Is it even possible to do this in a secure manner?
On a basic level, all HTTP communications are text data being passed back and forth between a client and a server. So, if you extracted the cookies from the Server X response and passed them in the request to Server A, then as long as A understood to extract the cookie data and insert the cookies into a new request to Server X, you would be successful in achieving what you are asking.
In a nutshell.. cookies are simply text data that gets passed back and forth between servers and clients. You can grab that data and pass it wherever you like. (you'd probably be breaking a lot of security best practices, though)
However... many servers are getting smarter about request forgery attacks and the fact that the remote host, client ip, etc... are different may invalidate the request or at least alarm Server X. So test thoroughly on all test/stage/prod platforms before making any blanket assumptions about the viability of the strategy.
If you control the behavior of the "rich client" then yes, sure. Just look at what cookies you have for the server you're about to access, if it includes your user login tracking cookie you're set, if not, look at the cookies for the other server and copy any user login tracking cookie that you have there, if it exists, into the cookie pool for the request you're about to make for that server.
Presumably, because you're trying to share users, the two servers share a user database that has common userIDs or other hashes which you're using in these cookies.
If on the other-hand, the only user tracking you have in place now is essentially session based, where the cookie contains a hash for the session and that session is stored on the server side, then unless the two servers share the session store, you will not be able to simply hand off identical cookies from the client side.
Related
I'm working on an app which will use CouchDB to store some data for users. But I don't want users to log into CouchDB directly.
I will have an app client (mobile/web), an app server, and the CouchDB server. The client app will authenticate to the app server, then myy ideal scenario would be for my app server to authenticate the users programmatically, then send just the 10-minute cookie to the client app.
That is, I would like the app server to request a Cookie from the CouchDB server on behalf of the user of the app client, then send only the cookie to the app client.
The app server could just POST to _session on behalf of the authenticated user, but this requires:
maintaining a list of users' passwords in the app server
using a single, known, password for all users
resetting the password to something random for each authentication request
For security reasons, #3 seems the best, but this seems like extra work, and is an extra round-trip to the DB (albeit, not an expensive one). So my question is: Is there any, as an administrator, way to generate a cookie on behalf of a user, without using the users' password at all?
This would also potentially allow me to entirely reject requests to _session except from my app server, as an added security measure.
And for the sake of completeness, I'll also mention that I've looked at these other options, and found them wanting:
Proxy Auth
The fact that the x_auth_token never expires is worrisome to me. It means a compromised token would grant forever access to the user's data. And AFAICT, the token can't even be invalidated without changing the user name or the server secret (which would in effect invalidate everyone else's auth tokens as well). But maybe I'm missing something here?
OAuth auth
This seems to just move the problem. Now rather than storing users' passwords in my server app, I have to store OAuth secrets. Plus, now my server and client code must be more complicated.
I don't follow your exact goals. You seem to imply users might have passwords ("app server authenticating the users programmatically") but you don't want the users to "ever need to know their CouchDB password". What sort of authentication do you want?
There's two (and a half) general approaches I've taken to authentication with CouchDB:
"Man-in-the-middle[ware]" approach, where I have thin middleware in front of CouchDB. This middleware forwards username/password to the "/_session" which yields a cookie or error codes based on the CouchDB _users database. The middleware copies this cookie from CouchDB onto its own HTTP response back to the client (or displays a message in case of error). Then on subsequent requests, that need database access, it forwards the cookie (now from the client request) back again to the database.
The traditional approach, where you just use CouchDB as a data store and maintain your own "user" entries/indexes. Make sure you use current best practices for password storage/handling or use a library that takes care of those details for you. The middleware connects to the database as "itself" and handles read/write permissions with its own logic based on its own session handling.
Or — sort of a hybrid approach — you can use the "/_session" API only to see if CouchDB accepts the username+password as valid. If it does, create a separate middleware-handled session for that user. (Basically you're only using CouchDB's _user database as the "password handling library" and the rest is the traditional approach where the access control is implemented all in the middleware rather than at the database.)
For real-world production stuff, I've tended to use only the latter two (or one-and-a-half given the earlier numbering…) — the first method is kind of fun, but CouchDB's lack of document-level read permissions usually means that giving users nearly-direct access to the database server is untenable in practice.
UPDATE: your question now makes it clear that you want the client app to talk directly to both servers: the app (formerly "middleware") server and the CouchDB (database) server. I'm leaving the content above because I think it's still somewhat useful and provides a bit of background/context for this update.
You are right in your suspicions that Proxy Authentication is the wrong solution: it is not intended for end-user usage, but really to replace the cookie-forwarding "trick" portion of #1 above. That is, proxy authentication is when you fully trust one party (i.e. your middleware) to provide the user information as it works on behalf of a user. But you want the users to talk to the database directly, and you cannot trust them with the X-Auth-CouchDB-Token.
I will defer to your judgement on the OAuth option. I do think it is closer to want you want but it is clear that somehow you are authenticating users against a different service and don't need to store per-user keys in CouchDB itself. The request signing required by OAuth 1.0 does mean you'd need support in your client app's HTTP library too.
I see a few options, without building a custom CouchDB plugin, that could let your app server hand out a token to authenticated users which your database server will accept:
Proxy after all! That is, hide your database server behind your app server or another lightweight custom reverse-proxy. All this middleware needs to do is check your existing client app session (cookie or other authentication header) and if it's valid, set the internal proxy auth headers that CouchDB will accept — then it forwards the rest of the request/response verbatim.
Deterministic password, per-user if it makes you feel better. Configure your app server with a secret known only to it, then set each user password to something like HMAC(username, app_server_secret). Now when you want to generate a token for a user, your app server can generate the password on a per-user basis. Note that this really isn't any more secure than just using the app_server_secret as the password for every user — CouchDB already salts and hashes each user password independently so if someone gets a hold of the database but not your app's configuration values the attacker couldn't tell the two apart. In both cases, preventing unauthorized database usage hinges entirely on keeping app_server_secret secret.
Re-implement CouchDB's current cookie generation algorithm. CouchDB's cookie algorithm (view source) is basically data = username + ':' + timestamp; base64(data + ':' + sha_mac(data, secret)). Where secret is the couch_httpd_auth.secret value plus the user's salt value. You can tell your app server the couchdb_httpd_auth/secret value and it can follow the same steps to generate a valid cookie which you provide to the client app, and CouchDB will accept it as its own. This cookie will be valid until the timestamp + the configured couch_httpd_auth/timeout. As "hacky" as it seems, this is probably the closest to what you are asking for, although you still need to set/disable the users' actual passwords somehow.
Expanding on natevw's brilliant answer. I was having similar problems, and never would have realized option 3 was possible without having stumbled across that answer.
Here is my python3 implementation for generating a cookie (uses pycouchdb to interface with couch):
def generate_couchdb_cookie(couchAddress, couchSecret, username):
timestamp = format(int(time.time()), 'X')
data = username + ":" + timestamp
server = pycouchdb.Server(couchAddress)
db = server.database("_users")
doc = db.get("org.couchdb.user:" + username)
salt = doc["salt"]
secret = couchSecret + salt
hashed = hmac.new(secret.encode(), data.encode(), hashlib.sha1).digest()
inbytes = data.encode() + ":".encode() + hashed
result = base64.urlsafe_b64encode(inbytes)
return "AuthSession=" + (result.decode("utf-8")).rstrip('=')
Correct me if I am wrong: In a traditional web application, the browser automatically appends session information into a request to the server, so the server can know who the request comes from. What exactly is appended actually?
However, in a API based app, this information is not sent automatically, so when developing an API, I must check myself if the request comes from an authenticated user for example? How is this normally done?
HTTP Protocol is stateless by design, each request is done separately and is executed in a separate context.
The idea behind session management is to put requests from the same client in the same context. This is done by issuing an identifier by the server and sending it to the client, then the client would save this identifier and resend it in subsequent requests so the server can identify it.
Cookies
In a typical browser-server case; the browser manages a list of key/value pairs, known as cookies, for each domain:
Cookies can be managed by the server (created/modified/deleted) using the Set-Cookie HTTP response header.
Cookies can be accessed by the server (read) by parsing the Cookie HTTP request header.
Web-targeted programming languages/frameworks provide functions to deal with cookies on a higher level, for example, PHP provides setcookie/$_COOKIE to write/read cookies.
Sessions
Back to sessions, In a typical browser-server case (again), server-side session management takes advantage of client-side cookie management. PHP's session management sets a session id cookie and use it to identify subsequent requests.
Web applications API?
Now back to your question; since you'd be the one responsible for designing the API and documenting it, the implementation would be your decision. You basically have to
give the client an identifier, be it via a Set-Cookie HTTP response header, inside the response body (XML/JSON auth response).
have a mechanism to maintain identifier/client association. for example a database table that associates identifier 00112233445566778899aabbccddeeff with client/user #1337.
have the client resend the identifier sent to it at (1.) in all subsequent requests, be it in an HTTP Cookie request header, a ?sid=00112233445566778899aabbccddeeff param(*).
lookup the received identifier, using the mechanism at (2.), check if a valid authentication, and is authorized to do requested operation, and then proceed with the operation on behalf on the auth'd user.
Of course you can build upon existing infrastructure, you can use PHP's session management (that would take care of 1./2. and the authentication part of 4.) in your app, and require that client-side implementation do cookie management(that would take care of 3.), and then you do the rest of your app logic upon that.
(*) Each approach has cons and pros, for example, using a GET request param is easier to implement, but may have security implications, since GET requests are logged. You should use https for critical (all?) applications.
The session management is server responsibility. When session is created, a session token is generated and sent to the client (and stored in a cookie). After that, in the next requests between client and server, the client sends the token (usually) as an HTTP cookie. All session data is stored on the server, the client only stores the token. For example, to start a session in PHP you just need to:
session_start(); // Will create a cookie named PHPSESSID with the session token
After the session is created you can save data on it. For example, if you want to keep a user logged:
// If username and password match, you can just save the user id on the session
$_SESSION['userID'] = 123;
Now you are able to check whether a user is authenticated or not:
if ($_SESSION['userID'])
echo 'user is authenticated';
else
echo 'user isn't authenticated';
If you want, you can create a session only for an authenticated user:
if (verifyAccountInformation($user,$pass)){ // Check user credentials
// Will create a cookie named PHPSESSID with the session token
session_start();
$_SESSION['userID'] = 123;
}
There are numerous way for authentic users, both for Web applications and APIs. There are couple of standards, or you can write your own custom authorization / and or authentication. I would like to point out difference between authorization and authentication. First, application needs to authenticate user(or api client) that request is coming from. Once user has been authenticated, based on user's identity application needs to determine whatever authenticated user has permission to perform certain application (authorization). For the most of traditional web applications, there is no fine granularity in security model, so once the user is authenticated, it's in most cases also and authorized to perform certain action. However, this two concepts (authentication and authorization) should be as two different logical operations.
Further more, in classical web applications, after user has been authenticated and authorized
(mostly by looking up username/password pair in database), authorization and identity info is written in session storage. Session storage does not have to be server side, as most of the answers above suggest, it could also be stored in cookie on client side, encrypted in most cases. For an example, PHP CodeIgniter framework does this by default. There is number of mechanism for protecting session on client side, and I don't see this way of storing session data any less secure than storing sessionId, which is then looked up in session storage on server-side. Also, storing session client-side is quite convenient in distributed environment, because it eliminates need for designing solution (or using already existing one) for central session management on server side.
Further more, authenticating with simple user-password pair does not have to be in all case done trough custom code which looks up matching user-record in database. There is, for example basic authentication protocol , or digest authentication. On proprietary software like Windows platform, there are also ways of authenticating user trough, for an example,ActiveDirectory
Providing username/password pair is not only way to authenticate, if using HTTPS protocol, you can also consider authentication using digital certificates.
In specific use case, if designing web service, which uses SOAP as protocol, there is also WS-Security extension for SOAP protocol.
With all these said, I would say that answers to following question enter decision procedure for choice of authorization/authentication mechanism for WebApi:
1) What's the targeted audience, is it publicly available, or for registered(paying) members only?
2) Is it run or *NIX, or MS platform
3) What number of users is expected
4) How much sensitive data API deals with (stronger vs weaker authentication mechanisms)
5) Is there any SSO service that you could use
.. and many more.
Hope that this clears things bit, as there are many variables in equation.
If the API based APP is a Client, then the API must have option to retrieve/read the cookies from server response stream and store it. For automatic appending of cookies while preparing request object for same server/url. If it is not available, session id cannot be retrieved.
You are right, well the reason things are 'automatic' in a standard environment is because cookies are preferred over URL propagation to keep things pretty for the users. That said, the browser (client software) manages storing and sending the session cookie along with every request.
In the API world, simple systems often just have authentication credentials passed along with every request (at least in my line of work). Client authors are typically (again in my experience) reluctant to implement cookie storage, and transmission with every request and generally anything more than the bare minimum...
There are plenty of other authentication mechanisms out there for HTTP-based APIs, HTTP basic / digest to name a couple, and of course the ubiquitous o-auth which is designed specifically for these things if I'm not mistaken. No cookies are maintained, credentials are part of every exchange (fairly sure on that).
The other thing to consider is what you're going to do w/ the session on the server in an API. The session on a website provides storage for the current user, and typically stores small amounts of data to take load off the db from page to page. In an API context this is less of a need as things are more-or-less stateless, speaking generally of course; it really depends what the service is doing.
I would suggest you send some kind of token with each request.
Dependent on the server and service those can be a JSESSIONID parameter in your GET/POST request or something mature like SAML in SOAP over HTTP in your Web Service request.
After creating a basic REST service, I've have come to the point where it would be appropriate to add some sort of password protection, as I need to verify that my users are both properly logged and have sufficient permissions to execute whatever action they are going to.
The REST service will mainly be accessed from a Javascript-heavy frontend and with that in mind, I have come up with the two following alternatives to solve this:
Make users login by first sending credentials to a /login page with POST. The page sets a session cookie wherein the user is
marked as logged in, along with the permission level. On each
following request, I verify that the user is logged in and his/her
permission level. When the session expires, automatically or
manually (logout, the user will have to re-logon).
Temporarily save the credentials hashed locally and send the users credentials along every single request made by the user to verify the credentials & permissions backend on a per-request basis.
Are there more ways to solve this and is there something else that I should be concerned with?
I'm currently developing a REST API along with a client (written in javascript), below I'll try to explain the methods used to protect the API against unauthorized access.
Make your REST API to require a Auth-Key header upon every request to the API, besides /api/authenticate.
/api/authenticate will take a username and a password (sent using POST), and return user information along side with the Auth-Key.
This Auth-Key is randomly generated after a call to /api/authenticate and stored in the backend users table with the specific user entry, a md5 hash of the remote ip + the user agent provided by the client.
On every request the value of Auth-Key, and the md5 sum mentioned, is searched for in users . If a valid user is found that has been active during the past N minutes the user will be granted access, if not: http return code 401.
In the REST client, first get the Auth-Key by posting to /api/authenticate, then store this value in a variable and send in on every future request.
If you want to stay true to the definition of a REST service then it should be stateless and not store any login (or other context specific) data on the server: http://en.wikipedia.org/wiki/Representational_state_transfer#Constraints
Your 2nd approach would fit this model
First decide what it is that you're protecting against:
Authentication? (Knowing who is requesting your service?)
Authorization? (Whether a given person can properly request a given service or not?)
I recommend that you provide hashed keys for your service. That way you can manage the key issue separately from the services. Or a client key and a secret, Amazon does this.
It is always easier for the client if you have a stateless protocol. And send everything through the parameters, cookies are a bother for the client too.
Remember that it is in your interest to make it as easy as possible for potential developers to use your service. A super secure service that no one uses is boring.
You can let clients choose the security level by giving them the choice of HTTP or SSL/HTTP endpoints to connect to. Client choice is a good thing.
Make users login by first sending credentials to a /login page with POST. The page sets a session cookie wherein the user is marked
as logged in, along with the permission level. On each following
request, I verify that the user is logged in and his/her permission
level. When the session expires, automatically or manually (logout,
the user will have to re-logon).
Temporarily save the credentials hashed locally and send the users credentials along every single request made by the user to verify the
credentials & permissions backend on a per-request basis.
Your first approach does not meat the statelessness constraint of REST. You cannot maintain client sessions on server side. This constraint makes REST highly scalable...
Your second solution is appropriate. The simplest way to use HTTP basic auth. You don't have to hash the password on client side. What you need is an encrypted connection. On server side you can have an [username, password] -> [identity, permissions] cache, so this solution is much faster and superior in every other way than having server side sessions.
By 3rd party (non-trusted) clients the authentication is more complex, I guess you don't need that part.
I'm no security-expert. I use the RESTful Play!-webframework and they do the following things to authenticate users.
The cookie is protected against manipulation. It is signed with a long secret key and is checked for each request. Just hashing it is not enough!
They recommend to set unique information the identify the user in the cookie. As the server should be the only one to manipulate the cookie, that's enough.
Don't put the password as credential in the cookie. If someone sniffs the cookie, not only the session can be hijacked, but also the complete account or even worse, other accounts with the same credentials.
If you want to protect the cookie against hijacking using https.
I have REST services that I was planning on protecting with Windows Integrated Authentication (NTLM), as it should only be accessible to those internal to the company, and it will end up being on a website that is accessible by the public.
But, then I thought about mobile applications and I realized that Android, for example, won't be able to pass the credentials needed, so now I am stuck on how to protect it.
This is written in WCF 4.0, and my thought was to get the credentials, then determine who the user is and then check if they can use the GET request and see the data.
I don't want to force the user to pass passwords, as this will then be in the IIS log, and so is a security hole.
My present concern is for the GET request, as POST will be handled by the same method I expect.
One solution, which I don't think is a good option, would be to have them log into Sharepoint, then accept only forwarded reqests from Sharepoint.
Another approach would be to put my SSO solution in front of these services, which would then force people to log in if they don't have credentials, so the authentication would be done by SSO, and since the web service directory could be a subdirectory of the main SSO page, then I could decrypt the cookie and get the username that way, but, that would be annoying for the mobile users, which would include the senior management.
So, what is a way to secure a REST service so that it is known whom is making the request so that authorization decisions can be made, and will work for iphones, android and blackberry smartphones.
I have the same problem so let me give you the details and would also appreciate feedback. Since you are using an internal system you have one extra option that I have listed.
My first option isn't perfect, yes it could be hacked but still - better than nothing. With each request you pass the device's unique identifier along with a hash. You generate the hash using a salt embedded in the application along with the id. On the server you match the incoming hash with one you generate at the server, with the passed unique identifier. If someone "roots" their device, and is smart enough they could find the salt - you can obscure it further but ultimately it could be stolen. Also, I keep all requests on SSL to just help hide the process. My "enhancement" to this process is to pass back new salts after each request. New devices get 1 chance to obtain the next salt or get locked out ... not sure about that step yet.
Now another approach, is to have the user enter a "salt" or username and password only an internal user would know - the device obtains a token and then passes it (on SSL) with each request. Nobody outside your company could obtain that so this is probably best. I can't use this since my app is in the app store.
Hope that helps! Let us all know if you ever found a good solution.
My current solution, in order to protect data in the system, is to force people to first log in to the application that the REST services support (our learning management system), as I have written an SSO solution that will write out a cookie with encrypted data.
Then, the REST service will look for that cookie, which disappears when you close the browser, and I don't care if the cookie is expired, I just need the username from it, then I can look in a config file to see if that user is allowed to use that REST service.
This isn't ideal, and what I want to do is redirect through the SSO code, and have it then send the person back to the REST service, but that is not as simple as I hoped.
My SSO code has lots of redirects, and will redirect someone to a spot they pick in the learning management system, I just need to get it to work with the other application.
I have a set of .NET applications running in a public web environment which connect to a centralized component made up of web pages and web services.
Is there any way to implement a security feature to make the centralized web pages be sure of the caller applications identity? Making a post and supplying a querystring parameter stating the caller application is a naive solution, someone can manually change it.
Any ideas? Tks in advance.
Assign secret keys to each client-server pair and use them to sign messages passed between client and server (using HMAC for example).
TLS/SSL/HTTP. You just need to enable client authentication. SSL is usually only used in the scenario where the server needs to be authenticated. But the server end can be configured to authenticate the client also. Digital certs need to be installed on both ends. This then uses all the appropriate crypto to do the job, ie. public authentication, establishment of secure channel, using Diffie-Hellman, RSA, AES/3DES, whatever you configure.
Take a look at this post. Good place to start.
Another option, perhaps have you look at OpenID?
The current situation:
Servers A, B, and C are trusted and controlled by you. A visitor comes to site A and views a page that sends data to site C, and the data contains something like "origin=A". We're concerned that the user will change that to "origin=B".
A simple fix:
You control all three servers, so let them communicate to verify incoming data. For example, A will change "origin=A" to "origin=A&token=12345", where the token value is random. The user tries to tamper with it and sends "origin=B&token=12345" to server C. C makes a trusted connection to B, saying "Did you send someone to me with token 12345?" B says "Nope" and C knows to reject the request.
This can be arbitrarily elaborate, depending on your needs and whether you're using https. Maybe tokens expire after a certain time period. Maybe they're tied to IP address. The point is that server C verifies any information that comes from the end user with servers A and B.
Are you asking about single-sign-on? (i.e. someone authenticated on AppA should also be able to use AppB and AppC without re-authenticating)
You can do this by configuring the machineKey for your apps so they can share asp.net authentication tokens.
The company I work for currently uses shared forms authentication cookies across the enterprise by using the same machine keys on each web server. However, this is not ideal if you wish to SSO across different domains and it's not very neat for windows app that need to come into the web farm to use the web service methods...
So, where we have to do this we are using SAML
But to clean this all up and make it more unified and more secure we are beginning to implement Geneva
If you communicate with the web services and web pages using http post, you avoid putting the info in a query string.
Send the data over https so that it cannot be tappered with.
You then need to make sure that the call is coming from your public web environment. One way of doing this is to use windows authentication, based on the identity of the application pool.
EDIT 1
Take a look at this link: http://www.codeproject.com/KB/WCF/WCFBasicHttpBinding.aspx
It shows how to set up windows authentication for WCF basic http binding.
Maybe look at the HTTP REFERER field. Under certain conditions this may be treated as reliable. In particular: An A mimic site won't send users from A to C according to HTTP REFERER.