1

I am using some web API that operates by providing an API key (40 character string).

Upon registration to this service, i (the developer) gets this key which is unique per user.

Every call to the API looks something like a POST call to:

http://www.someservice.com/api/method

Where the actual data passed in the request contains:

apiKey=myKeyHere....

My question is -- how can i prevent users of my app revealing this API key?

This specific service provides highscore storage for games. Making my API key easily accessible means that players of my game will be able to issue their own requests for registering highscores.

I would like to either HARD CODE it into the code (less ideal solution) or keep it in some binary/configuration file that cannot be used to determine the actual string.

The scenario i would like to prevent is users getting this key, and submitting messages using it to the server instead of my app.

lysergic-acid
  • 17,990
  • 18
  • 96
  • 194
  • 3
    Short answer? You can't, for power users. For lusers, any old obfuscation will probably do. Possible duplicate of [How do you hide an encryption key in a .NET application?](http://stackoverflow.com/questions/619921/how-do-you-hide-an-encryption-key-in-a-net-application) and a zillion others – bzlm Feb 18 '12 at 15:29
  • 1
    It does not matter. I'll just sniff your traffic. And if you use SSL, I just hook the point where the plaintext goes into your SSL library. – CodesInChaos Feb 18 '12 at 15:30
  • @CodeInChaos, you can't. That would violate the EULA. – bzlm Feb 18 '12 at 15:30
  • The traffic is HTTPS so you cannot sniff in the middle. – lysergic-acid Feb 18 '12 at 15:31
  • the data is sent using POST using HTTPS, so listening/sniffing will not help. – lysergic-acid Feb 18 '12 at 15:32
  • @bzlm Why would anybody that wants to extract a secret key from an application care about a EULA? Either he's playing nice, then simply embedding an obvious key into the executable is fine, or he's not, that as long as you're using this network protocol he'll trivially get the key. – CodesInChaos Feb 18 '12 at 15:32
  • @liortal SSL won't help you. Just put a breakpoint on `SslStream.Write` and collect the key. – CodesInChaos Feb 18 '12 at 15:33
  • @CodeInChaos, relax, I'm kidding. :) liortal, SSL won't help you. You really need to re-think your security strategy in general, and make it so sniffing/reverse-engineering/etc doesn't harm you in particular. – bzlm Feb 18 '12 at 15:34
  • @liortal, in your situation, I'd recommend that you post your data to a proxy web service that you personally host. You can then send your data encrypted or packed with enough authentication information -- notice that it will NOT be easy to defeat all hackers. Your proxy web service in turn posts the authenticated data to the real web service using your apiKey. This way, the key never leaves your server. – Stephen Chung Feb 19 '12 at 08:01
  • Yes that can work, however this at least partially defeats the purpose of integrating an external service instead of rolling my own service. – lysergic-acid Feb 19 '12 at 08:30

2 Answers2

6

As long as you use such a simple protocol where a static unchanging key is sent to the server, your key obfuscation doesn't matter. The attacker can simply sniff the traffic, and extract the key.

You'd need a heavily obfuscated piece of code, that produces a one time(or short term valid) key. That might deter weak attackers, since they need to either reverse-engineer or duplicate your key producing code. But against a competent attacker this will fail too.

You should not see client side API keys as a security measure. They behave more like the user agent header in http. The only API keys that can be secure, are those stored on a server controlled by the App developer, such as in a third party web application consuming your API.

CodesInChaos
  • 100,017
  • 20
  • 197
  • 251
-2

To protect it in memory, you can use SecureString.

To encrypt it in some local storage (such as configuration file specific to user or the machine), you can use ProtectedData.

If you need to transfer it between the systems, you can use one of many encryption algorithms available in System.Security.Cryptography, such as: RSACryptoServiceProvider.

Branko Dimitrijevic
  • 47,349
  • 10
  • 80
  • 152
  • 2
    Using those just puts a beacon on it. These classes only protect against a very narrow range of attacks, and are not helpful here. – CodesInChaos Feb 18 '12 at 15:29
  • I would like to prevent users from having access to this key, since it would allow them to send messages on my app's behalf to the server, which is something to be avoided. – lysergic-acid Feb 18 '12 at 15:30
  • @CodeInChaos I don't understand why are they "not helpful here". Care to clarify? – Branko Dimitrijevic Feb 18 '12 at 15:32
  • @BrankoDimitrijevic, because the idea here is to protect the API key from users actually possessing and running the application. Essentially, it's the user running the application that's handing the API key to the service, which means secure strings and whatnot are completely irrelevant. We're not protecting against people who *aren't* running the app (men in the middle, other users on the computer, etc). – bzlm Feb 18 '12 at 15:36
  • @liortal How do you distinguish between users that can send messages and those that can't? – Branko Dimitrijevic Feb 18 '12 at 15:37
  • 2
    Those APIs protect against accidentally leaving the key in RAM too long, or it accidentally turning up in memorydumps. But it doesn't protect at all against an attacker who controls the system your program runs on. – CodesInChaos Feb 18 '12 at 15:38
  • @bzlm What's the purpose of API if no one can call it? – Branko Dimitrijevic Feb 18 '12 at 15:40
  • My app knows the key so it can use it to submit data to the server. Other people shouldnt know the key – lysergic-acid Feb 18 '12 at 15:42
  • @BrankoDimitrijevic, dafuq? I think you need to read the question again. :) – bzlm Feb 18 '12 at 15:42
  • @CodeInChaos `SecureString` can be helpful in obfuscating memory. Public/private key encryption can be helpful in protecting the data in transport. OTOH, if somebody can actually attach a debugger and step through the code, well then all bets are off - but then again API should never rely on client validation anyway - no matter _how_ the API is called, it should work correctly. – Branko Dimitrijevic Feb 18 '12 at 15:44
  • @bzlm You said: "the idea here is to protect the API key from users actually possessing and running the application". That implies no one can actually _use_ it. Surely, _some_ users are allowed to use the application? – Branko Dimitrijevic Feb 18 '12 at 15:53
  • I asked the question.. The idea is to never expose this key, since it is used to submit high score data. Reveal the key, and every user of the app can submit his own high score. – lysergic-acid Feb 18 '12 at 15:57
  • @liortal Let me see if I get this right: user logs in with her password, and receives the key identifying the session. That key is then used for the rest of the session. You are worried about a different user stealing that key and submitting its own "high score" instead of the original user. If so, what's to protect the original user from his **password** being stolen in the first place? If you can trust users to keep their password safe, you can trust them with the session key (provided you encrypt it in transport) and vice-versa. – Branko Dimitrijevic Feb 18 '12 at 16:09
  • 1
    @BrankoDimitrijevic He wants to make sure that his application is the only one that can use the API. i.e. he wants to lock out third party implementations. In particular he wants to prevent the user from submitting a faked highscore. This is not about per-user secrets/passwords. – CodesInChaos Feb 18 '12 at 16:15
  • @BrankoDimitrijevic no this is not the scenario. Many services today work by registering, receiving an API KEY (unique for every registered developer). This key is used for requests to the service (alongside other data). For example, when updating highscore data i would submit a request to http://www.api.com/highscore with data that contains API_KEY and other parameters. I would like to keep this key privately without letting the user have the ability to get it (or at least make it hard to get it). – lysergic-acid Feb 18 '12 at 16:16
  • @CodeInChaos Well them, unless user has a motivation to guard the key (or an application is in a physically secured "kiosk"), this is impossible. – Branko Dimitrijevic Feb 18 '12 at 16:30
  • @liortal Then you have an open design. Change your design. You **have** to somehow motivate your users to guard the key - trying to guard it purely at the application level can never be completely safe. OTOH, if you only need to make it _hard_ to get, then using techniques in my answer will help. – Branko Dimitrijevic Feb 18 '12 at 16:34
  • Nothing in your answer helps with obfuscation on making it hard to hide a key. – CodesInChaos Feb 18 '12 at 17:00
  • @CodeInChaos Sure is does. Never store it in memory as plaintext and never transport it as plaintext. That won't prevent somebody tenacious enough from eventually reverse-engineering it, but it does make it harder. – Branko Dimitrijevic Feb 18 '12 at 17:17
  • @liortal, most modern services already have support for this scenario, either by outsourcing security (via eg. OAuth) or by some other means (eg. servicifying what you currently have as an app). If you tell us more about your situation, we may be able to provide more help. Otherwise, you could think about putting your own service in front of the other services, hiding the API key for the third-party services from your users, who would only have *your* service API key, or whatever the equivalent would be. – bzlm Feb 18 '12 at 18:57