On API keys...
Mark Waddingham
mark at livecode.com
Fri Jun 24 13:04:06 EDT 2022
So this is mainly aimed at Tom Glod due to a question he asked in this
afternoon's Feature Focus session which I perhaps did not answer
particularly well (and given that it is security related, I figured I
should expand on what I said).
The question was whether putting an API Key as a LiveCode 'constant',
rather than anything else, made it 'more secure' - the answer is 'no
more than putting it anywhere else in a password protected script'.
However, what I should have probably expanded on is what my
understanding on the best practice for API keys in general is...
I have come across three kinds of API key in practice:
1) API keys intended to be used from web pages (in client-side code)
2) API keys intended to be used in deployed apps
3) API keys intended to be used for doing secure things
How I would advise using them (based on my current understanding, at
least) is:
TYPE 1
In (1) above you have things like Google Analytics 'product ids' (which
aren't strictly API keys I guess, but are similar enough to warrant
inclusion) and Google Maps JS keys.
As these are intended to be used in client side JavaScript - there is
very little, if anything, you can do to protect them directly.
For Analytics, since the worse that can happen is that someone can
generate fake analytics it doesn't really matter - and the data can be
relatively easily filtered and processed to eliminate any dodgy looking
submissions.
For Maps, it can cost you money if someone else tries to use yours -
however, you can restrict the key by the referring website and IP
addresses, as well as what the key can do.
TYPE 2
In (2) you have things like Google Maps App keys (for Android/iOS) - and
all manner of other 'cloud type' services which have (native) app
bindings for mobile (and desktop).
Many services offer restrictions for these keys too - for example Google
Services API keys can be restricted by Android app signing hashes and
ids, and iOS app bundle ids.
However, in general, these services generally suggest that you ensure
that the API key is not extractable directly from the app bundle (after
decompressing in general) - i.e. that the key be obfuscated in some
fashion and does not appear in plaintext.
It is important to note that they do not require any more than this
because, at the end of the day, any API key has to be in memory at some
point, and indeed has to be transmitted 'over the wire'. If someone has
enough access to access memory, then they have enough access to
intercept the HTTP requests (even if encrypted - if they really know
what they are doing) so obfuscating in the on-disk files of the app is
as good as you can get.
If these keys are compromised then it is a pain - it might cost you
money (as all these services which have them tend to charge by use) -
and, if embedded in an app, will require an app update to replace.
TYPE 3
Certain services require (sometimes in the TOS!) that their API keys
*never* leave a secure bubble which you control - this means they must
never appear in deployed apps or in files transmitted to the browser.
Payment gateway API keys will pretty much always fall into this category
- Stripe is a good example.
The only way to use these keys is from server scripts running on a
server which you do your best to maintain the security of. Ideally these
keys should be stored in files which are only readable by specific users
- usually the web-server user which is running the backend scripts which
needs to make the requests.
Indeed, services which require this tend to design their APIs for the
intention of being used on a server.
WHAT TO DO IN LIVECODE
If you are dealing with a type 1 key then you really don't have to worry
- they are designed to be used in a context which offers zero ability to
protect them, so including them in a deployed app (in particular) is
more secure out of the gate than in their intended use in a webpage.
[ Of course, whether you are actually *allowed* to use their services
from anything other than websites is another matter - and entirely
defined by their TOS - but I digress! ]
If you are dealing with a type 2 key then the requirements put on their
use in deployed (native) apps is more than catered for by having the key
in script, in a password protected stack - for example, as a constant
return value of a function, or indeed as a constant defined in the
script which is talking to the API. With this, the key will not appear
in plaintext in any of the files included in the built app (even after
the container is unzipped).
[ I should note here that custom properties values also do not appear in
plaintext in any of the files of a built app - however, having them in a
password protected script offers an extra level of protection ].
If you are dealing with a type 3 key then you must only use that key via
a server - this means you need to set up server side scripts which your
app then talks to via a suitable protocol (e.g. HTTP / REST) to perform
the operations which use it. The key must never be sent over the wire
between your app and the server as this could be intercepted by someone
who is using your app locally.
BEST PRACTICE FOR APPS WHICH REQUIRE USER LOGIN
Of course, the most secure way to use API keys of all types is to have
them only ever on a server - however, this is only really suitable if
your app is 'always online' and you can do all operations on the server
- many services this doesn't work, e.g. Google Maps. However, there is a
reasonable middle ground which offers a little more security (and
convenience, in the case of compromise!).
If your app can only be used by a user *after* they login locally then
the best practice for type 1 and type 2 keys (as mentioned previously
type 3 keys must NEVER leave your server!) is to not store the keys in
the deployed app at all.
Instead, once the user has successfully authenticated have the server
send the API keys the app needs to use. You can either do this once per
session, or if your app allows 'offline' use as long as they have signed
in before (on mobile) you can use something like the 'secureKey' library
to store them in the mobile devices 'trusted' store.
This approach has two main benefits:
1) The API keys are never actually in a file someone can sit and
dissect at will (even obfuscated, there are some very persistent bad
actors out there!)
2) If your API key is compromised (or you do need to change it, for
whatever reason) you can do so without having to have everyone install
an app update with the new one in.
Anyway, that's probably more than Tom probably needed to know (or
perhaps knew already), but hopefully it is helpful (at least for those
who have to deal with API keys and such things!).
Warmest Regards,
Mark.
--
Mark Waddingham ~ mark at livecode.com ~ http://www.livecode.com/
LiveCode: Everyone can create apps
More information about the use-livecode
mailing list