130

Lately I've seen plenty of APIs designed like this:

curl "https://api.somewebsite.com/v1/something&key=YOUR-API-KEY"

Isn't it elementary that passing an API key in a query string as a part of the URL is not secure at least in HTTP.

Future Security
  • 1,701
  • 6
  • 13
Incerteza
  • 2,207
  • 3
  • 16
  • 22
  • 3
    It is not a good practice to pass sensitive information in URL. In the above case, I am sure that the server must be doing some additional validation (validating the session cookie etc.) after receiving the request from the client. – roguesecurity Mar 30 '16 at 08:41
  • 2
    Possible duplicate of [How does SSL/TLS work?](http://security.stackexchange.com/questions/20803/how-does-ssl-tls-work) – Tobi Nary Mar 30 '16 at 08:50
  • 12
    @PiyushSaurabh, it's rest api, what cookies? – Incerteza Mar 30 '16 at 10:50
  • 77
    it's worth noting that with HTTPS the hostname (api.somewebsite.com) is passed in the clear but the full URL is not, so it will not be susceptible to casual traffic sniffing attacks in that case. – Rory McCune Mar 30 '16 at 11:36
  • 1
    @RоryMcCune, it's not? why not? – Incerteza Mar 30 '16 at 12:14
  • 22
    @アレックス The TLS handshake is completed (using the domain part of the address) before the specific path is requested - the path is therefore within the encrypted traffic - see http://security.stackexchange.com/a/20847/89876 for full details. – Matthew Mar 30 '16 at 12:48
  • 2
    On many web servers all URLs requested are logged to a file (e.g. access.log) in clear text. – Michael Mar 30 '16 at 19:52
  • 13
    The reason you don't put passwords in a URL normally is because *they show up in browser history and in the URL bar*. Those are irrelevant if the client is not a browser. – user253751 Mar 31 '16 at 04:25
  • @アレックス that would likely depend on the server in question. In many cases they would store full URLs and I would regard that as a downside of placing tokens in URLs , although it's likely (depending on the threat model) less of a concern as the attacker would need access to the server. – Rory McCune Mar 31 '16 at 08:28
  • 3
    Api key is often only one part of the authentication, the public one. There usually is the other, secret part that's never sent, only used to calculate checksums. We can't really tell what "api key" means here, so we can't say if it's really a secret. It might be as well used purely for statistics. – Agent_L Mar 31 '16 at 09:03
  • Possible duplicate of [Use of obscure URL for security](http://security.stackexchange.com/questions/91837/use-of-obscure-url-for-security) – Ben Voigt Mar 31 '16 at 20:36
  • 1
    Secure against what threats? As our [help] says, "Security is a very contextual topic: threats that are deemed important in your environment may be inconsequential in somebody else's, and vice versa. [...]To get the most helpful answers you should tell us: what assets you are trying to protect; who uses the asset you're trying to protect, and who you think might want to abuse it (and why); what steps you've already taken to protect that asset; what risks you think you still need to mitigate". Please edit the question to provide more detail about these aspects. – D.W. Mar 31 '16 at 22:16
  • One other consideration with putting secrets in URLs is that URLs are often logged in clear text in access logs and be available long after the calls have completed. You would need to either avoid logging this or secure these logs to meet your requirements. – JimmyJames Apr 01 '16 at 21:02
  • Don't think that POST data won't be logged by the server. See this module for example http://httpd.apache.org/docs/current/mod/mod_dumpio.html – rjdown Apr 01 '16 at 22:42
  • Possible duplicate of [Is including a secret GUID in an URL Security Through Obscurity?](http://security.stackexchange.com/questions/36870/is-including-a-secret-guid-in-an-url-security-through-obscurity) – kalina Apr 04 '16 at 08:00

4 Answers4

163

This is commonly known as a capability URL / secret URL.

It's secure in modern websites but not suitable for all applications and requires significant care to use.

You can find an excellent overview of their advantages, risks and best practices in this page by W3C.


It's meaningless to talk about security without specifying a threat model. Here are a couple that come to mind:

  • 1: A passive attacker on the network (eavesdroping)
  • 2: An active attacker on the network (can change packets at will, mitm, etc)
  • 3: A shoulder-surfer
  • 4: An attacker with physical access to your computer / elevated privileges
  • 5: another user of your computer (regular privileges / remote access)
  • 6: the user itself (as in protecting a API key)

Regarding network attacks (1 and 2), capability URLs are perfectly secure, provided you're using HTTPS (it's 2016, you shouldn't be using HTTP anymore!).

While the hostname of a server is sent in plaintext over the network, the actual URL is encrypted before being sent to the server - as it's part of the GET request, which only occurs after the TLS handshake.


Regarding shoulder-surfing (3), a capability URL with enough entropy is secure against a casual attack, but not against a dedicated attacker·

As an example, a google docs URL:

https://docs.google.com/document/d/5BPuCpxGkVOxkjTG0QrS-JoaImEE-kNAi0Ma9DP1gy

Good luck remembering that while passing by a co-worker's screen!

Obviously, if your attacker has a camera and can take a picture without being noticed, it's an entirely different matter. If the information you're securing can put your users at risk of this kind of attack, you should probably not use a capability URL. Or at least mitigate the issue by doing a HTTP redirect away from the capability URL, so it's only on screen for a few seconds,


Regarding an attacker with elevated privileges on your computer (4), a capability URL is not less secure than a long password or even a client-side TLS certificate - as all of those are actually completely insecure, and there's not much you can do about that.

An attacker with regular privileges (5), on the other hand, should not be able to learn the capability URL as well, as long as you follow good security practices for your OS. Your files (particularly browser history) should not be readable by other users.

If you share your computer account with other people, this is also horribly insecure. A good rule of thumb for shared computers is to not use them to access any information you'd not speak out loud in the street.


For protecting API keys (6, which was the point of this question), a capability URL is also as secure as a less visible mechanism (such as an AJAX POST). Anyone that has an use for an API key will know how to use the browser debug mode to get the key.

It's not reasonable to send someone a secret and expect them not to look at it!


Some people have asked about the risks on the server side.

It's not useful to treat server-side risks by threat modelling in this scenario. From a user perspective, you really have to treat the server as a trusted third party, as if your adversary has internal network access on the server side, there's really nothing you can do (very much like a privileged attacker on the client's computer, i.e. threat model 4 above).

Instead of modelling attacks, I'll outline common risks of unintentional secret exposure.

The most common concern with using capability URLs on the server side is that both HTTP server and reverse proxies keep logs, and the URL is very often included.

Another possibility is that the capability URLs could be generated in a predictable way - either because of a flawed implementation, a insecure PRNG, or giving insufficient entropy when seeding it.

There are also many caveats that have to be taken into consideration when designing a site that uses capability URLs.

In practice, for sites with dynamic content, it's quite hard to get everything done securely - both Google and Dropbox botched it in the past, as mentioned on this answer


Finally, capability URLs have a couple of advantages over other authentication methods:

  • They are extremely easy to use (just click the link, as opposed to entering your email and password)
  • They don't require the server / service to securely store sensitive user credentials
  • They are easily shareable without risks, unlike sharing you password (which you reuse for 50 other sites).
loopbackbee
  • 5,338
  • 2
  • 22
  • 22
  • @アレックス A url with a secret component - i.e.: one that you wish an attacker not to know about. In your example, it would be the API key – loopbackbee Mar 30 '16 at 15:36
  • 1
    Here is another threat model that can occur in a corporate environment: the server has other users who have read-only access to the http logs. In this case any user on the system can see every URL the server serves. – Michael Mar 30 '16 at 19:49
  • @Michael True. There's a million things that can go wrong on the server side, logs (both on servers and reverse proxies), bad use of PRNGs, insecure software implementation... From a user perspective, in practice, you have to assume that the server is a trusted third party – loopbackbee Mar 30 '16 at 21:20
  • 5
    These URLs are known as "capability URLs" in some places. A good discussion can be found here: https://w3ctag.github.io/capability-urls/ – Martin Thomson Mar 30 '16 at 23:16
  • 3
    If implementing such a thing, remember that most webservers log the url, which might or might not be desirable. – Johannes Kuhn Mar 31 '16 at 03:58
  • 1
    Although you have a good argument. I actually disagree. URL's are logged and often with the query. That means API keys will be stored somewhere in a text file reachable by the sys admins. One can argue that the content can also be logged. That is true, but, by default it's not so common. – nsn Mar 31 '16 at 07:53
  • I think you should mention "timed secret urls" That is URL with a secret encoded part that expires after a specific time. – Hogan Mar 31 '16 at 21:23
  • Re: 5: other users can see command-line arguments for any process on many systems (any Linux?) by default. – Ry- Apr 01 '16 at 00:22
  • @RyanO'Hara While it's good to always be aware of that, it's not really specific to capability URLs (the same thing happens when you use a password) – loopbackbee Apr 01 '16 at 18:07
  • 1
    Nice reply. One of the nice things about URLs is that they are so sharable. I email them to people all the time. So they really shouldn't contain information more secret than the resource they identify. E.g. a URL that I use for a public file on a drop-box type site should not contain a capability that lets someone see private files. – Theodore Norvell Apr 01 '16 at 21:24
  • http://www.securityweek.com/hackers-can-intercept-https-urls-proxy-attacks – Tom Jul 29 '16 at 14:40
24

It depends on how that API is meant to be used and what type of data it is accessing. Something that accesses google maps (for example) is much lower risk than something accessing banking data.

Obviously a call like that in client side code is insecure, the user can easily learn your API key.

If the API call is made server to server, then it's less of an issue.

Using HTTP would leave the connection open to eavesdropping, HTTPS removes that problem.

Another problem with keys in the URL is the full url ends up in log files. That expands the attack surface for the app, as there are now more places to look for the key.

To answer your question, It's not that passing keys in the URL is inherently insecure, rather it's less secure than alternatives and not best practice. Assuming the API isn't accessing something sensitive, the connection is over HTTPS and the call is made server to server, it should be 'good enough' for low risk services.

Jay
  • 1,575
  • 1
  • 10
  • 12
  • 1) how does https remove this problem if the url is always in plain text? 2) if it wasn't something sensitive, there would be no api key. 3) it's curl, it's not server to server. – Incerteza Mar 30 '16 at 10:52
  • https prevents eavesdropping only. i.e. no one else 'on the wire' can see the call going past. sensitive is relative, yes it has a key so its something to restrict access too, but banking/health data etc are far more sensitive than accessing a map api. yes its curl, but you don't make curl requests from javascript.you dont have to use curl to invoke that api – Jay Mar 30 '16 at 10:58
  • 36
    **Why would you assume that accessing Google Maps would be less dangerous than accessing banking data?** I happen to know one guy who would prefer that hackers empty his bank account than his wife find out where he goes on lunch breaks. The point is, when designing a secure system, you **cannot make any assumptions**. – dotancohen Mar 30 '16 at 13:06
  • 2
    "Obviously a call like that in client side code is insecure, the user can easily learn your API key. " A user can just as easily learn an API key that is sent in any other way - it's their computer. A user that is not technically able to get an API key from a POST request wouldn't have much use for it! – loopbackbee Mar 30 '16 at 13:20
  • 11
    @dotancohen the API key for Google Maps (as far as I know) is just to keep track of how many calls are made to the Maps API from your app, because free users have a limit. So there shouldn't be a security risk like finding out specific locations. However, I see your overall point and I agree with it. – DasBeasto Mar 30 '16 at 13:24
  • @dotancohen I see your point, maps and banking where just examples, I was also under the impression that google maps only use the key to monitor usage limits. thats the problem with examples, they never really fit all scenarios. – Jay Mar 30 '16 at 14:32
  • 1
    In the age of Machine Learning it's important to treat all data as secure. It's just too easy to reveal minor details (like sleep schedules) from API emissions and other items traditionally thought of as "low risk." – Dave Mar 31 '16 at 18:20
  • 3
    I think whenever we discuss web security, there is always the assumption that the two parties engaged in the dialog trust each other at least to some extent. If I send you an encrypted message, it's ok for both you and myself to know the contents of the message. The security is there to prevent third parties from accessing it. So all arguments about log files on the server, or debug console in the browser etc. are irrelevant; if the server *is* the attacker then no, this is not secure. And if we send the client a message then yes, he can read it. – Stijn de Witt Mar 31 '16 at 18:49
10

It is not a good idea to pass secrets as GET parameters in general. I compiled a list on my blog a while ago on the potential security issues:

Secrets may leak to other parties as the following:

From your computer / smartphone

Server-side

  • Web server logs
  • Log aggregating services such as SIEM, Elasticsearch, Splunk
  • Log files indexed by search engines (relevant Google dork)
  • Reverse proxy logs

To Third-parties

  • Proxy logs (e.g. in an enterprise environment)
  • Exception reporting services such as Rollbar or Sentry
  • Other websites via the Referer header
  • A friend, in case the URL is shared in an email or IM message
  • Fellow tenants in a public cloud

Some of them is not applicable to Ajax requests, but ymmv

Gabor
  • 179
  • 5
0

I wonder why nobody explicitly mentions the risk of session fixation and CSRF vulnerabilities. Of course you can mitigate these by adding CSRF tokens and implement secure session handling but this implies that you actually have control over the relevant code.

Since this question has the title A secret in a URL some people could come to the conclusion that it's sufficient if they implement some mitigating measures around instead of seeing it as possible attack vector which can be avoided.

Noir
  • 2,553
  • 13
  • 23
  • could you elaborate on session fixation? – Incerteza Jul 30 '16 at 05:10
  • 1
    I'm not clear on what you mean here. CSRF attacks (the ones I'm familiar with) work by tricking a browser into automatically sending user credentials when performing an action (one that requires authentication) on some other site. This works because the secret is stored as a cookie and sent automatically by the browser. In this case we're discussing a secret (e.g. credentials) that is stored in the URL (not cookie), so nothing is sent automatically. Or are you talking about the risk of CSRF when secrets *are* stored in the cookies? – Codebling Aug 17 '20 at 00:45