[HN Gopher] OpenAI API keys leaking through app binaries
___________________________________________________________________
OpenAI API keys leaking through app binaries
Author : archiv
Score : 114 points
Date : 2023-04-13 15:47 UTC (7 hours ago)
(HTM) web link (twitter.com)
(TXT) w3m dump (twitter.com)
| simonw wrote:
| Things I'd like to see from OpenAI API keys:
|
| - Unlimited, or at least a much higher limit - right now they are
| restricted to 5
|
| - Ability to set a time limit on a key - I'd like to create a new
| key that's only good for the next hour when I try out a new thing
| that asks me to paste in an API key
|
| - Abiliy to set a budget for an API key. Giving an app a key with
| a $5 total budget - or $10/month or whatever - would be really
| neat.
|
| - OAuth support. Let me OAuth connect an app with my OpenID
| account - then I don't have to know what an API key is, I can
| grant it permission to spend my API credits, and I can revoke
| access later
|
| - Let me see how much money each API key has spent
|
| - An option to log everything an app does with my API key would
| be cool - I already have ChatGPT logs and rely on them all the
| time, but having that for other random applications would be
| excellent.
| sharemywin wrote:
| I would think you would keep an api wrapper around it at least
| probably some kind of IP tracking and auth.
| steve_adams_86 wrote:
| I'm surprised people wouldn't want to route requests through a
| backend so they could throttle traffic and prevent abuse from a
| place no one else can control. Perhaps they simply don't know
| that's a concern -- they put a static API key for a service that
| costs money into a client side application. That seems
| unintentional, at least in regards to exposure to potential
| consequences.
| binarymax wrote:
| Keeping creds safe is basic security practice, and we have the
| eternal September of programmers - which now applies to
| inexperienced people using AI to cobble together software. So
| there's going to be a lot of these mistakes made and learned as
| they acclimate.
| matisseverduyn wrote:
| Noticing that comments like this are being consistently
| downvoted, yet there doesn't seem to be any sort of
| disagreement in the replies. Usually when people disagree
| online, they don't merely downvote, but also post their
| dissent.
|
| _Interesting_ that it 's suddenly become so "controversial"
| to suggest circumspection with respect to this subject...
| hutzlibu wrote:
| I didn't downvote, or noticed such a pattern, but was this
| comment really insightful? It just said, programming newbs
| will make newb misstakes. Yes and? I mean it is self
| evidently true. So yes, you can say it and the wording was
| not really condescending, but quite often to me it is just
| bashing beginners to feel more powerful and smart as an
| experienced and studied programmer, compared to those
| amateurs.
| matisseverduyn wrote:
| > Keeping creds safe is basic security practice... So
| there's going to be a lot of these mistakes made and
| learned as they acclimate.
|
| This might not be insightful from your perspective,
| because you've thought about it before, but it needs to
| be said. Just like a NO DIVING sign in the shallow end,
| most people already know, but some people who don't know
| might not know if it isn't stated.
| SketchySeaBeast wrote:
| To stretch/extend/mangle your swimming metaphor - the AI
| tools now let people swim in the deep end before they've
| taken their water wings off. There's lessons that others
| would probably learn along the way by having to do a lot
| of searching and parsing of the basics that can be
| skipped over now.
| hutzlibu wrote:
| I am not sure. Also before ChatGPT you could google and
| copy and paste some foreign code together you did not
| understand, even before stackoverflow. In fact, this is
| what I did as a beginner and I would think most did. You
| start to modify and play a bit with it and after a while
| you understand (something). Or you try until it somewhat
| works.
|
| I don't see, why ChatGPT changed that, I only tried it a
| little bit so far, but it doesn't usually give you a
| ready program, right? It gives you snippets, that might
| work, or not, but in my case required understanding of
| the domain. So I could adopt the scripts to my need, but
| I doubt a beginner could. At least not for anything non
| trivial. Also those beginners can ask a million stupid
| questions to the AI that just patiently answers. So yes,
| those answers can be wrong, but that can happen in a
| forum as well and even in university occasionally I was
| taught some BS.
|
| So yes, ChatGPT changes the game a bit, but not that
| drastic. If you want to become a professional programmer,
| you still have to get your hands dirty and grind away the
| basics. But you cannot skip certain things, or you never
| manage to get even a mid sized project running performant
| and stable.
|
| And if necessary, it would be probably trivial to weed
| out "programmers" that aren't really programmers by
| asking them some questions directly.
| SketchySeaBeast wrote:
| I think ChatGPT reduces a lot of the friction - you can
| ask it to piece things together quickly and it produces
| it in a more easily digestible format, especially when
| compared to the google + read cycle. I know some people
| are trying to learn things with ChatGPT when they
| wouldn't before - it's easier to build something in a
| conversational manner and it's harder to pick up the
| pieces when StackOverflow steers you wrong.
|
| I agree with your assertion that non-trivial things will
| weed out "programmers", I just think that ChatGPT will
| get people further and that definition of "non-trivial"
| will shift a bit - possibly far enough people will have
| an easier time leaking their API keys through
| Frankenstein apps they post online.
| iudqnolq wrote:
| It seems like static hardcoded API keys are a best practice
| with map APIs. I'm guessing because of the large number of
| requests in the critical path proxying adds to much latency?
| But everyone does it.
| klausa wrote:
| People who make iOS apps rarely are equally comfortable with
| creating backend apps; for understandable reasons.
| outcoldman wrote:
| Lol. Posted about it a month ago. And reported that to some devs.
| https://twitter.com/outcoldman/status/1636742564887011329?s=...
|
| Nothing is going to change.
| black3r wrote:
| You should never store ANY secret information (API keys,
| passwords, tokens, secret keys of any kind) in your application
| binary. It can always be extracted one way or another..
|
| If your application needs to call a 3rd party service like
| openAI, the only solution to safely not leak your API key is to
| have your app only communicate with a backend you own and call
| the openAI from there.
|
| OpenAI allows revoking leaked keys. If you did include your API
| key in a client-side application, update your app to use a
| backend for openAI API communication, use a fresh key and revoke
| the old key when your update ships (or if you value security over
| functionality then revoke the key before you ship the update).
| dheera wrote:
| Almost all Google APIs that have any kind of visualization
| component that runs on the client (for example, an embedded,
| pannable Google map with things drawn on it) require you
| shipping your API key in your clients.
|
| They have some safeguards e.g. HTTP referrer restrictions but
| it's not bulletproof.
| black3r wrote:
| Google Maps's "API key" is not really a secret. It's used
| only to identify your application and to generate an iframe
| that's only allowed to be used on your website. It's
| bulletproof enough not to be considered as a secret as it
| can't really be used to impersonate your app if leaked.
| ElevenLathe wrote:
| > If your application needs to call a 3rd party service like
| openAI, the only solution to safely not leak your API key is to
| have your app only communicate with a backend you own and call
| the openAI from there.
|
| I've also seen vendors do things like issue client-side keys
| for AWS IAM users that can access their backend (in AWS) with a
| super locked-down role. This would be more interesting as a
| solution if IAM stuff was interoperable between cloud providers
| (CSP), since this dependency means you can't move to another
| CSP without bothering your customers. It also doesn't help in
| the OpenAI case because there isn't a way to mint limited-
| permission tokens.
| 0xEFF wrote:
| Given a cloud service account you can call the provider's
| token service, get a bearer token, then use that bearer token
| to call any other cloud service configured to trust the
| provider issuer. Most cloud providers support this today with
| oidc.
| mrbombastic wrote:
| That may be true but I would hazard a guess that 90% of mobile
| apps that talk to 3rd party services have keys stored in their
| binaries. It may be true as an individual that you should not
| do that but discipline doesn't scale. We need a convenient best
| practice that doesn't put keys in the binary. Setting up a
| proxy server that you also need authentication with that talks
| to all your apis is not gonna get done unless you make it idiot
| proof.
| PaulWaldman wrote:
| >the only solution to safely not leak your API key is to have
| your app only communicate with a backend you own and call the
| openAI from there.
|
| Don't you still have the same problem? Your backend would also
| require a key for the client to communicate, which would still
| be embedded in the client binary.
| Gravyness wrote:
| Yes, but you could negotiate a token with each user on
| startup and if someone starts abusing your service you can
| block that access (perhaps automatically) or know who it is
| by authenticating the user.
| [deleted]
| survirtual wrote:
| No.
|
| You go through traditional auth channels (username /
| password) or you generate a key per app user to talk with
| your backend.
|
| Or, you keep the backend you control open and implement
| controls to combat abuse, such as rate limiting and ip
| blacklisting.
|
| Whatever chosen, the objective is to protect your API key and
| make sure the application is being used according to its
| purpose.
|
| An API key directly to openAI allows for any use under the
| sun -- botnets, new prompts, etc., and can drain money, put
| your account in bad standing, or even get you in (potentially
| serious) legal trouble. Using your own backend, you can do
| things like hit the openAI moderation endpoint, inject the
| correct prompts into whatever you're sending to openAI, etc.
|
| The main thing is you have a limited API specific to your app
| offering which significantly lowers the damage possible. You
| absolutely always want to give users the least privilege
| necessary for whatever use cases being provided for -- this
| protects both you and your users.
| counttheforks wrote:
| You have a different problem. You can handle the
| authentication, and blacklisting, on your side. That's harder
| to do when the clients communicate with OpenAI or another
| third party directly, while incurring charges that you have
| to pay for.
| CuriouslyC wrote:
| No, your proxy site can have a login flow or some other
| unique id process that is per client like any web app.
| joe_the_user wrote:
| Well, if you have an app that's a thin structure on top of
| GPT-4, adding your own pipe between your client and OpenAI
| could add a lot to the cost and complexity of the app. Which is
| to say it's not surprising that people don't do it.
|
| The genius and the craziness of GPT-4 is you can make whole app
| with a prompt like "now you're a clown painting custom faces on
| kids based on their favorite animals" and some glue-code.
| Needing to add a 3 layer network infrastructure with isn't
| appealing I'd imagine.
| mousetree wrote:
| Could be as simple and cost-efficient as a Cloudflare worker
| that adds your key and passes the query along
| lucakiebel wrote:
| Or a 5EUR/mo Hetzner server running Nginx, though
| Cloudflares free offering is very generous
| jeffy90 wrote:
| You'd need some kind of authentication as well.
| pxx wrote:
| Errrr, I assume your app can pass said authentication? If
| so, then it's meaningless; that's again a secret not
| under your control.
| de6u99er wrote:
| Not only that, but it makes not much difference if they call
| the GPT Api directly or through a proxy. Only thing that
| eould really help is having users register and authenticate
| through the proxy.
| ceejayoz wrote:
| The proxy approach at least lets you rate limit by IP,
| limit the length of the strings (and thus the token cost),
| etc. The API key may also grant access to other models,
| administrative IPs, etc. you don't want people using.
|
| Far, far, far better than nothing.
| klausa wrote:
| This is advice so broad and generic, that it's just about
| useless.
|
| If you don't store any API keys in your binary, how do you
| handle crash-logging and analytics? How do you integrate with
| third-party log-in SDKs?
|
| You _could_ vend some of those (not the crash-logging ones,
| etc) from your API, but then how do you authenticate to _that_,
| if you can't have any secrets?
|
| You can't login-gate all of those, and many of those are not
| easily rotated.
| black3r wrote:
| There is a difference between an app ID and a secret. A
| secret is something that can be used to impersonate you or
| your app towards a 3rd party service if leaked.
|
| 3rd party log-in SDKs using OpenID connect can work entirely
| without client-side secrets using only your app IDs. Crash
| logging and analytics services API keys are also usually
| considered to be app IDs, not secrets.
| mrbombastic wrote:
| Sure but now the advice is what? first determine which of
| these 10 api keys your app uses are really secret, for
| those that aren't just stick em in the binary and you are
| done, for those that are set up a proxy server with
| authentication, store the keys on that, and call the apis
| through there. ...or you could stick all 10 in the binary
| and be done in 5 minutes. Can you start to see why it is so
| common that people just stick api keys in the binary? Can't
| we have some reasonable dev experience for storing secrets
| that isn't 10x the effort?
| black3r wrote:
| Determining which API key is supposed to be a secret
| isn't usually an issue, cause typically site providing
| you with the secret key clearly states the fact that it's
| supposed to be a secret. For example this is what OpenAI
| says about their keys directly on the page where you
| generate the key: "Your secret API keys are listed below.
| Do not share your API key with others, or expose it in
| the browser or other client-side code."
| hospitalJail wrote:
| > is to have your app only communicate with a backend you own
| and call the openAI from there.
|
| I'm a bit baffled anyone puts anything secret on software
| people are using. This service needs to be online anyway.
|
| Anyway, seems like a lazy programmer thing.
| judge2020 wrote:
| Running a server even to proxy requests takes a lot of work,
| since you now need your own auth system and have to manage
| scaling. If you take the plunge, a serverless architecture
| like Cloudflare Workers makes scaling automatic, but you
| still have to do some heavy lifting to either have an API key
| or auth system and abuse protections (otherwise they just
| spam your API instead of directly stealing your OpenAI api
| key).
| psychphysic wrote:
| Er.... Just ask gpt4 to how to do it obviously.
| counttheforks wrote:
| You probably don't need to scale if all you're doing is
| auth and proxying requests. If you get to the point where
| you do need to scale, you can probably afford to figure it
| out.
| politician wrote:
| Or, a lazy ChatGPT auto-generated code copy-paste thing.
| tikkun wrote:
| If you want a solution that isn't perfect, but is at least
| slightly better:
|
| Store the key in your code but in a basic encrypted string, and
| then decrypt it at runtime.
|
| Yes, it's still easy to get if someone is motivated, but it's a
| lot harder to read the machine calls figuring out what method was
| used to encrypt the string (make it a method that can't be
| figured out from only the encrypted string), than it is to read
| the plaintext key from the Plist.
|
| Bad in theory, helpful in practice.
| andrewmunsell wrote:
| As others have mentioned in the thread, this doesn't guard
| against a MITM proxy and it'd take a couple minutes to defeat
| this.
|
| You're much better off proxying calls from your own server API,
| having proper rate limits and authentication, and a strict API
| surface that doesn't permit arbitrary calls to whatever APIs
| you depend on
| weird-eye-issue wrote:
| Fine for some secrets but I'd never do with something like an
| OpenAI key. Somebody could blow through your entire months's
| usage allowance before you notice anything
| kgeist wrote:
| There's a lot of sites leaking OpenAI keys on the frontend as
| well, including some projects posted here on HN. I contacted one
| such dev back in February, they said they would fix it ASAP, and
| it's still not fixed.
| hijohnnylin wrote:
| For some developers, this is sort of intentional. The reason is
| at least twofold:
|
| 1) Calling OpenAI directly is one less hop, so user gets lower
| latency
|
| 2) Not having to set up / maintain a backend server = get to
| market faster
|
| There are some very popular GPT apps recently that are obviously
| putting their API keys on the client side - won't name them but
| they've been featured quite a bit.
|
| The downside is not as bad as people think. Worst case, someone
| takes your key and what, plugs it into their own app, costing you
| a few bucks?
|
| - OpenAI keys have a hard budget limit that requires manual
| approval by OpenAI anyway
|
| - Not much privacy risk - unlike other API keys, OpenAI APIs
| don't allow you retrieve previous data AFAIK. There are some APIs
| to fine-tune models, but I seriously doubt any of these consumer
| apps are doing this now.
|
| - You can just create a new version later and revoke the old key.
| And now you've broken the thief's app.
|
| My guess is the developers were well aware of the tradeoffs. Just
| felt it was more important to get to market faster, than to
| batten down all the hatches. They're probably right?
| RichieAHB wrote:
| You could probably remove the OpenAI qualifier from this finding,
| but I guess it makes it more relevant.
| ohgodplsno wrote:
| Note: it's probably not just iOS/MacOS apps. Android apps are
| equally vulnerable to this if you're brazen enough to dump your
| key in any .xml file. Or in your code if you just run strings on
| it.
| gumballindie wrote:
| Why dont they use a server for forwarding requests to openai and
| not exposing any keys? That way they can easily ab test various
| ai engines and secure their keys. It is known.
| cypherpunks01 wrote:
| Even if you store API keys in code inside a distributed binary,
| isn't it pretty simple for users to mitmproxy and view API
| requests containing there keys sent? There's no real way to
| control API keys given out to users - if you want to hide them,
| you just have to proxy requests instead.
| KMnO4 wrote:
| There's a really good iOS app called Proxyman[0] (the Mac app
| is also excellent) that lets you view HTTP requests that apps
| make from inside iOS.
|
| If you're curious about this sorta stuff, I definitely
| recommend checking it out.
|
| [0]: https://proxyman.io/ios
| mrbombastic wrote:
| Some people do cert pinning to prevent this, but generally yes
| it is pretty simple.
| thewataccount wrote:
| You can't do cert pinning if you're using the openai api
| directly though?
|
| That only applies for internal api calls, at which point the
| requests/binary won't contain the openai key?
| varenc wrote:
| Ehh, I don't think it'd be that hard to implement cert
| pinning against OpenAI's APIs.
|
| You just need some very permissive pinning, where you
| require any publicly trusted CA, to prevent MITM attacks.
| Basically only trust the root CAs a phone already trusts by
| default. You don't need coordination between the server and
| your client to implement this. All you have to do is
| prevent your TLS calls from trusting any certs signed by
| manually trusted CAs that Proxyman/Charles/etc might have
| had the user add.
|
| Of course, that'll only delay the API keys leaking. With a
| jailbroken iPhone and Frida you can effectively disable
| cert pinning checks. Or extract the keys from memory, or
| binary analysis, etc.
| mrbombastic wrote:
| Yeah you are correct, only really can be done with apis you
| can control, even then it is a pain bc you need the certs
| and app in lockstep. But for example if your proxy api used
| an api key and you wanted an additional layer of security.
| Edit: sibling comment is interesting for an approach that
| might remove low hanging fruit
| lcfcjs wrote:
| [dead]
| ncann wrote:
| Isn't API key pretty much can always be recovered client side? If
| API key is hardcoded in the app it's trivial to get. If it's
| dynamically fetched it's also trivial to intercept the network
| call. I don't think there's anything you can do to prevent that.
| UltimateEdge wrote:
| The replies suggest storing the API key on a backend which you
| control.
| speedgoose wrote:
| You can have a server side proxy for authenticated and
| authorised users, with a rate limit.
| numpad0 wrote:
| From comments here, I suppose you could make your app cloud-
| based so your client app is just a UI and only your trusted
| backend has full access to the external API, and that sounds
| dystopian.
| agentwiggles wrote:
| Why is that dystopian? Sounds like the standard, good-idea
| architecture for an application that communicates with a paid
| 3rd party API.
| hagbarth wrote:
| It's... pretty normal practice.
| GrinningFool wrote:
| That's what these applications are already doing. The only
| difference is their cloud back-end is openai's API instead of
| something they control themselves.
| devit wrote:
| Well, the safe approach is to either have the user provide
| their own API key, or to perform requests on the backend (after
| verifying the user has an account, correctly authenticated, has
| paid and deducting from their quota).
|
| Or you could generate a per-user subkey with a quota if the
| upstream service supports that.
| thewataccount wrote:
| Yeah you can try obfuscating it, but in general you need to
| assume plain text access to anything you send the client.
|
| The only exceptions are basically some really hardcore DRM like
| denuvo and hardware certificated drm. Even those aren't safe
| from deteremined people.
| kgeist wrote:
| OpenAI API has a larger surface area than just completions. You
| can retrieve files uploaded through it, you can generate
| images, you can use the embedding API, you can use a different,
| more expensive model (GPT4) - and make as many calls as you
| wish. With a backend, you can restrict what is allowed, add
| your own rate limiting, you can rotate keys etc.
___________________________________________________________________
(page generated 2023-04-13 23:02 UTC)