54

According to https://developers.google.com/maps/documentation/javascript/tutorial#HTML5 , it seems I can add the following tag to my html and start using maps js API.

<script async defer
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>

But this will reveal my API key.

After searching on google and browsing answers on stackoverflow, I feel that maybe there is no need to hide this API key. I just need to set the referer when I create the API key on google, as explained in https://stackoverflow.com/a/2256312/1316649

So, even others know my API key, they cannot use it from another domain. Am I right?

But google says you shouldn't embed API key in code: https://support.google.com/cloud/answer/6310037

So, do I need to hide API key when using google maps js API? If so, how?

Update: By 'API key', I meant browser API key.

Community
  • 1
  • 1
fstang
  • 5,607
  • 4
  • 25
  • 26
  • 1
    If the api key has to do with your domain only, what difference does it make if others can see it? – Adam Buchanan Smith Jul 01 '16 at 20:56
  • 3
    I think the cloud support answer is a catch all on security for a variety of Google services that use keys. Since your Maps key is tied to your domain you don't need to worry about it (and can't do anything anyway) – j08691 Jul 01 '16 at 20:57

9 Answers9

36

While the above answers are helpful, none of them addresses the following vulnerability:

Once a user has access to your API key, even if they are restricted to using it only from your domain, they can still use it as much as they want. In the crudest sense, this could mean a million page refreshes (and map loads) in a very small amount of time, consequently putting you over your usage quota.

I haven't come across any solutions that address this issue. Unless I'm missing something...?

Relevant usage limits for google maps javascript api here.

Murcielago
  • 1,030
  • 1
  • 14
  • 24
  • 1
    I don't think anything can be done about that without some kind of own back-end implementation to restrict hammering. – Håkan KA Nov 30 '17 at 15:24
  • 4
    I'm upvoting because I was searching for posts that talked about the problem of malicious users exhausting the quota, but I don't think this really attempts to answer the question. – Kevin Workman Dec 02 '18 at 23:25
  • 2
    this is the problem I need to address – Blue Clouds Aug 09 '19 at 10:25
  • You can restrict the API keys. Your quota would not be affected. – isopach Dec 04 '19 at 08:25
  • 1
    You can restrict quotas per ip per 100seconds or per day - https://www.youtube.com/watch?v=A8bsgHUYsq8 – Daniel Jeney Sep 23 '21 at 14:09
  • 1
    Assuming you are on an infra that has access to a gateway/reverse proxy/ingress etc, you could always use a rate limiter. Could even create your own with a bit of creativity and possibly a serverless function. – Brandon Miller Oct 21 '21 at 19:38
  • 3
    This might help > [Maps JavaScript API Usage and Billing  \|  Google Developers](https://developers.google.com/maps/documentation/javascript/usage-and-billing#set-caps) You can limit number of requests in 3 ways. 1. Map loads per day 2. Map loads per minute 3. Map loads per minute per user – Kay. T Jan 01 '22 at 08:05
35

You can create multiple API keys with different restrictions to use them safely. For embedding a map, the Google Maps documentation has instructions for creating a correctly restricted API key so that it cannot be abused for other purposes at Get an API Key - Restricting API keys. It's OK to include a restricted API key in your source code, because you cannot embed a map properly without doing that anyway.

If you need server-side API access, you can create a second API key with less restrictions. That one should be kept secret.

Matti Virkkunen
  • 63,558
  • 9
  • 127
  • 159
  • Thanks for the answer! I'm asking about the browser key. I will update the question. – fstang Jul 01 '16 at 21:23
  • There is a API for geolocation by javascript. It suppose to be hidden as it is staten in the tutorial, so I did a function only to get it on fly silently - but it is always the same key! The information about those keys are unclear in Google Dev, thanks for clarifying! – Gustavo Nov 11 '17 at 17:05
  • Google no longer distinguishes between key types, and all security options are available on all keys (at writing time of Nov 2020). See https://cloud.google.com/docs/authentication/api-keys – sirlark Dec 15 '20 at 09:28
  • @sirlark Thanks. I've updated the answer to reflect how things work now. – Matti Virkkunen Dec 15 '20 at 10:59
5

To hide an API key for any service:

  1. Design a web server that will accept requests for the third party service and proxy requests to them.
  2. Design your graphic interface to make requests to the web server that you designed in step 1.
  3. Store the key on the web server you built in step 1, and apply authentication, authorization and rate limiting to the 3rd party proxied requests.

The 3rd party libraries that you use to build an interface in step 2 might force you to use certain hosts or might force you to include an API key. For the first problem, you'll have to either edit their library code, or provide the 3rd party client library with a different http request library, like redefining the fetch() function in javascript for example. For the second problem, just add a garbage key and your proxy server can ignore it and re-write it with the real key.

Benefits:
  • Hide your keys.
  • Track who, what, and when for requests and responses. You could do this other ways though.
  • Could add a layer of caching to the service to speed up requests that other users have made before, provided that their terms of service allows it.
Caveats:
  1. Because users will be making requests pretending to be your server, you are accepting a security risk. If the user intentionally makes maliciously formatted requests, they are doing so while appearing to be your server. You can however log all requests if you want to audit them later.
  2. It takes more than a couple seconds to build and configure the proxy server with all the security you require.
  3. You now need to handle all of these web requests which may be a lot of traffic.
  4. You may want to intercept the responses the server returns in case it returns the key in the response body during in an error or otherwise.
  5. You are adding another link in the chain and it will make the service slightly less reliable.
Mentions

I wanted to mention that this is essentially what "@OLTO and SUGI-cube Project" was trying to demonstrate in their answer and what #Brandon Miller was suggesting as a solution in a comment.

ADJenks
  • 2,973
  • 27
  • 38
4

The link that you posted that says you shouldn't embed API keys in code is related to Google's Cloud Platform. You are fine to leave your API key for Google Maps in your code.

  • 2
    Not sure this answer is extremely helpful, as Google Cloud Platform is where you get the Maps API key in the first place. See https://developers.google.com/maps/documentation/javascript/get-api-key – bers May 24 '20 at 20:55
3

No need to hide API key, you just have to make it useless, You can simply use key restrictions on the google API console.

from google API console choose:-

  1. credentials
  2. choose your API key or create a new one
  3. Application restrictions
  4. HTTP referrers (websites)

and then add your Website restrictions

Ahmed Taha
  • 121
  • 2
  • 12
1

I would recomend restricting your API keys to only be used by the IP addresses & referrer URLs that need them: By restricting the IP addresses, referrer URLs, you can reduce the impact of a compromised API key.

You can specify the hosts and apps that can use each key from the console by opening the Credentials page and then either creating a new API key with the settings you want, or editing the settings of an API key.

This should help you to secure your API keys.

Jeff

Jeffrey
  • 27
  • 1
  • 8
    Restricting referer does absolutely nothing, anyone can spoof it. And restricting over IP can't be done for public page like contact page, because you can't list all visitors IPs. – Martin Zvarík Dec 20 '18 at 00:09
-1

The two most accepted ways I have seen are to either use the [@googlemaps/js-api-loader]1 Or to - and this is important - restrict your keys the way google tells you to.

Brandon Miller
  • 1,534
  • 1
  • 11
  • 16
-1

Hello there,

Even if it's too late to post an answer I believe this would help the community, so i have worked out a solution that will hide the script tag from the DOM, I managed to do it by deleting the script tag after loading the script OR if it were an error while loading it, So here is the proposed solution and I'm happy to hear from you if it doesn't fit:

<script>
    const deleteMapScriptTag = () => {
        document.body.removeChild(
            Array.from(document.body.getElementsByTagName('script')).find(
                (item) => 
                    item.src.includes('https://maps.googleapis.com/maps/api/js?key=')
                )
            )
        }
</script>

So that part will search for the google maps script tag and remove it from the document, and we will call it after the

onload, onerror

events provided by the script tag as demonstrated below :

<script onload="deleteMapScriptTag()" onerror="deleteMapScriptTag()"
    src="https://maps.googleapis.com/maps/api/js?key={YOUR_API_KEY}&libraries=places"></script>

this will remove the script tag from the DOM as soon as it loads or fails loading, preventing users from inspecting the file and acquiring your key.

Although removed from the DOM, the original script tag (and therefore the key) will still be visible when viewing the page source.

Additionally, the full URL of the script can also be inspected via the Network requests panel in developer tools which also exposes the API key.

sjay
  • 3
  • 3
-2

You need to hide API key

You need to hide API key when using google maps js API. It is not enough for you to set the referer. I have local web server on my PC and can change my hosts file, So that I can spoof domain name of my HTML as your domain. If you reveal your API key in your HTML, someone might access Google map with that key. This could mean a million page refreshes (and map loads)!

This is bad example from Google.

<script defer
  src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>

How to hide API key from HTML

I use Environment Variables and CGI to hide my API key from HTML as follows.

1. set Environment Variables

I set Google Maps API key in Environment Variables and passing it to my CGI scripts. nginx + fcgiwrap are running on my server, so I set API key in my fcgiwrap.conf like this.

fcgiwrap.conf

location /cgi-bin/ {
    ........
    fastcgi_param GOOGLE_MAPS_API_KEY  YOUR_API_KEY; <= SET YOUR API KEY HERE
}

2. make CGI script

I made python CGI like this. This is same as src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY in SAMPLE of Google.

getapijs.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests
import os
url = 'https://maps.googleapis.com/maps/api/js'
key = os.environ['GOOGLE_MAPS_API_KEY'] # get Environment Variables
mysrc = url + "?key=" + key
response = requests.get(mysrc) # get src from Google Maps url
print("'Content-Type': 'text/javascript; charset=UTF-8'") # header for HTML
print("")
print(response.text)

3. call CGI from javascript

call your CGI from window.onload. This is same as <script defer ... &callback=initMap> in SAMPLE from Google.

main.js

function initMap() {
    var uluru = {lat: -25.344, lng: 131.036};
    var map = new google.maps.Map(document.getElementById('map'), {zoom: 4, center: uluru});
    var marker = new google.maps.Marker({position: uluru, map: map});
}
window.onload = function() {
    fetch("/cgi-bin/getapijs.py").then(res=>{
        return res.text();
    }).then(mytext => {
        eval(mytext);
    }).then(() => {
        initMap();
    }).catch(() =>{
        // error handling
    });
}

4.read main.js in your HTML

set <script src="main.js"></script> in your header section.

index.html

<!DOCTYPE html>
<html>
  <head>
    <style>
      /* Set the size of the div element that contains the map */
      #map {
        height: 400px;  /* The height is 400 pixels */
        width: 100%;  /* The width is the width of the web page */
      }
    </style>
    <title>Hello World</title>
    <script src="main.js"></script>
  </head>
  <body>
    <h3>My Google Maps Demo</h3>
    <!--The div element for the map -->
    <div id="map"></div>
  </body>
</html>
  • 4
    This does not help to hide the API key very much. An ajax request is still made which contains the key - users are still free to view that request and look at the key. Also, if they use inspect element in their browser, they are likely to find the key that way too. – Matthew Dresser Dec 18 '20 at 11:30
  • Thank you for your information. I have found APIKEY in ajax result js-text just now. This can hide APIKEY only from published source like on GitHub. Once execute this on my server, everyone could know my APIKEY. What shall I do then? I want to hide MYKEY. Can anyone help me? – OLTO and SUGI-cube Project Dec 19 '20 at 01:04