A developer emailed us earlier today with a good observation: If I release my Openomy application open source, how can I protect my application key and private key?
This is a problem that Ian and I have been thinking about since we decided that Openomy/RSS should be open sourced. For RSS, we stored the keys in a configuration file, and then asked users to go onto Openomy, create the application directly on the site, and then copy/paste the keys into the configuration file.
This works, but it's FAR from ideal: I wouldn't want to explain to my mom how to do that.
So to kick off discussion on here, we'd like to show you all our solution to this problem. We haven't implemented this yet, se please give us any feedback you may have!
We will do it via the APIs, and integrate it with the non-web app authentication process:
1. The application makes Auth.RegisterApplication API call: it supplies the application name, description and version as arguments, and gets an "apptoken" back.
3. Openomy asks the user to login, it displays the application's information (sent in step 1), and asks the user to authenticate the application. The user authenticates it, and goes back to the application.
4. The application calls Auth.GetApplicationCredentials using the apptoken from step 1. If the user authenticated the application, the API call returns an application key, private key, and the user's confirmedtoken.
5. Now the application has all of the pieces it needs to use the APIs normally.
We like this solution because it doesn't cause any extra burden on the users. One thing to note, however: these two API calls are different from all the others-- they dont require an application key or a signature to call.
I was also puzzled about login while writing OCW. I releasd it open source and provided both application key and private key, because I dont want to anybody to input more complicated string. For the end user it's too complicated to create an application by himself in openomy. But the risk is that the application will be abused. I'm not sure if someone else can get other's files through authorized application. What's the role about "unconfirmed token"? In my mind, I think everyone should provide their "unconfirmed token" while access their files, like a password. Or authorize the application with a url after login in the web. In the following source code: unconfirmed = a.GetUnconfirmedToken uri = Openomy::Util.new().GetAuthUrl(unconfirmed) puts "Please go to #{uri} to authorize this application." puts "When you have done this successfully, please hit Enter."
$stdin.readline @unconfirmedtoken = unconfirmed Is the unconfirmed token created randomly and assigned to the user forever? I think so because i can save the unconfirmed token for later use.
In your above non-web app authentication solution, if the appliation is released open source, u can still get private key. In fact i am still mazed a little with application token, private key and unconfirmed token now. The simple way that I like is to login with user's name and password.
We agree that we don't want to force users to create the applications themselves.. which is why we proposed this new method.
No, you can't get at someone's files by just knowing the application and private keys-- you would at least need the user's confirmedtoken as well. However, those keys are what authenticates your application to openomy and what makes sure that the api calls you make are actually coming from you. While this may not be super important now, it may be in the future.
Unconfirmed tokens are generated randomly. The transition from unconfirmed token to confirmed token is designed to make sure that the application was correctly authorized before API calls are made and to check that the application that the user authorized was the one that the user expected. If you are going to store anything, store the confirmed token (this is what Openomy/RSS does). Currently, confirmed tokens don't expire and keep working unless the user decides to de-authorize the application.
We didn't allow API calls to authenticate users via username/password on purpose: we don't want applications to be able to snoop a user's password. Also, in the future, we are planning on letting users to define permissions on their files (ex: This application only has read access to my files)-- which is insecure if authentication is done via straight username/password.
If after using this method, the application saves the appkey/privatekey in a configuration file, then yes, a user can access them. however, the point is that these keys are unique to the user's own installation of the program-- it doesn't matter if they know it at this point. In fact, the result of this method is identical to if the user went on the site directly and authorized the application by hand.
> I was also puzzled about login while writing OCW. I releasd it open > source and provided both application key and private key, because I > dont want to anybody to input more complicated string. For the end user > it's too complicated to create an application by himself in openomy. > But the risk is that the application will be abused. I'm not sure if > someone else can get other's files through authorized application. > What's the role about "unconfirmed token"? In my mind, I think everyone > should provide their "unconfirmed token" while access their files, like > a password. Or authorize the application with a url after login in the > web. > In the following source code: > unconfirmed = a.GetUnconfirmedToken > uri = Openomy::Util.new().GetAuthUrl(unconfirmed) > puts "Please go to #{uri} to authorize this application." > puts "When you have done this successfully, please hit Enter."
> $stdin.readline > @unconfirmedtoken = unconfirmed > Is the unconfirmed token created randomly and assigned to the user > forever? I think so because i can save the unconfirmed token for later > use.
> In your above non-web app authentication solution, if the appliation is > released open source, u can still get private key. > In fact i am still mazed a little with application token, private key > and unconfirmed token now. The simple way that I like is to login with > user's name and password.
I agree with the importance of private key now. But if the user got appkey/privatekey, he would write a new application and redistribute it by using same keys. Is it dangerous?
About 'unconfirmed token', it's generated randomly. But it seems that I can store and use it later. If i have a appkey/privatekey/unconfirmedtoken(which generated before), i can always get the confirmed token now without authoring to the url. It's unsafe. The confirmed token can be avaiable, but i think that unconfirm token should be expired. How about changing the transition from unconfimed token to confirmed token?
Permissions is a good idea like a local file system. It's better to create group and grant the permission.
Hey Bin, Thanks for the comments, it's much appreciated as we sort out these issues and make sure the service is both easy to use and has a good sense of security.
I'm not sure I understand your first question completely, but I'll just say that it's dangerous (and shouldn't be done) to *ever* distribute both your applicationKey and privateKey. Of course, your applicationKey will be seen by those using your service (it's how you identify in URLs for the API calls, so it will be seen). But distributing both your applicationKey and privateKey is bad because it allows anyone to pose as you (you being your application). You should never, ever want that.
Our proposed solution above does away with having to ever distribute your applicationKey and privateKey because it allows you to simply obtain an applicationToken for each user (which will later turn into an applicationKey and privateKey through authorization). An applicationToken could essentially be equated to a "partially created application." Think of it as an application with no owner, almost. Because all applications must have owners -- and because you need an applicationKey and privateKey to actually make API calls -- you can't actually do anything with an applicationToken. So, what happens is you send a user to the login page, and we tell them to confirm authorization to the app you asked for through your applicationToken (that is, you created a "partial application" with a name and description and received back an applicationToken).
The good stuff comes when the user confirms the authorization. First, we complete the creation of an application, with the user being the owner. Then the user returns to your application and you call Auth.GetApplicationCredentials to receive the applicationKey and privateKey.
This is now the new applicationKey and privateKey which you store in the user's application configuration, but do *not* distribute to anyone else. Every single user of your program can simply call the Auth.RegisterApplication call and get a unique applicationToken which can turn into the applicationKey and privateKey combination you need.
In response to your questions about unconfirmedTokens and being able to use them multiple times: it's true, you can reuse an unconfirmedToken. This is not necessarily *too* insecure, but it's at least a point which one could contend that we should force unconfirmedTokens to expire once they've created a confirmedToken.
The reason it's not *too* insecure is because a talented user could get at the confirmedToken just by snooping on URL traffic. The cool thing is it doesn't really matter until they break the hash and can figure out what the privateKey is. As long as that is sufficiently hard (and, unfortunately, with more powerful CPUs, it's getting easier to do that), it's still sufficiently hard to do anything useful with the APIs. As long as we stay ahead of the curve on cracking hashes, we should be okay. At least, I think... Can anyone contend this?
Hopefully this helps clear up some points. Let us know about other questions/comments, of course.
Sorry, I don't express myself clearly. My first question is to the last paragraph of Maurice: "If after using this method, the application saves the appkey/privatekey in a configuration file, then yes, a user can access them. however, the point is that these keys are unique to the user's own installation of the program-- it doesn't matter if they know it at this point. In fact, the result of this method is identical to if the user went on the site directly and authorized the application by hand. "
I agree with the importance of private key. And I dont think that i'll public privatekey again. But if the application is treated as opensource, how do the end user use it? Use there own appkey/privatekey by creating a application, or use the developer's? It's not convenient that users create application by themselves. And it's insecure for developers that users use another appkey/privatekey.
Aah, okay. Well, let me try to explain what this proposal accomplishes in different words:
Basically, if you have an open source app, you don't include ANY applicationKey or privateKey. Instead, you program a call to the APIs (Auth.RegisterApplication) with a name and description of your open-source application. This returns an applicationToken, which you then use to send the user to the web site to authenticate with (just as if it were any other app needing authorization). This returns a *new* and *unique* applicationKey and privateKey, just for *this instance* (i.e. this user) of your open source application. So everyone who installs your open source app will then get a *different* applicationKey and privateKey.
So what we think this accomplishes is creating an application seamlessly without the user even knowing it, while also keeping security by not publishing any applicationKey/privateKey.