Secure Google Maps Static API (Web) With Signed Url (Python)

Sep 13, 2020

You can secure you API Key (Google Cloud Console -> Credentials)

  • Create separate API keys for Web/Android/iOS/Backend.
  • For web, you can secure it by Application restrictions using HTTP referrers, and fill in Website restrictions on list of websites allowed.
  • You can further secure API restrictions by specifying which API this key could access.

The things is restriction via HTTP referrers is not really secure, as people still could access it via empty or spoofed HTTP referrers.

To secure Google Maps Static API (Web) from abuse, you need to use signed url.

First thing we want to do is disable access from unsigned url.

  • Goto https://console.cloud.google.com/google/maps-apis/quotas, and select Maps Static API.
  • Expand Unsigned requests (if URL signing secret is defined), and set the quota to ZERO
    • Unsigned requests (if URL signing secret is defined) per day: 0
    • Unsigned requests (if URL signing secret is defined) per minute: 0
    • Unsigned requests (if URL signing secret is defined) per minute per user: 0

If you try to load static maps without signature/signed (e.g. https://maps.googleapis.com/maps/api/staticmap?center=35.01856,135.68077&markers=35.01856,135.68077&zoom=16&size=370x300&key=YOUR_KEY&sensor=false), it will show This site can't load Google Maps correctly.

Now, you need to get URL Signing Secret.

Sign your URL (Python 2.7 example)

import hashlibimport hmacimport base64# import urllib.parse as urlparseimport urlparsedef sign_url(input_url, secret):    if not input_url or not secret:        raise Exception("Both input_url and secret are required")    url = urlparse.urlparse(input_url)    # We only need to sign the path+query part of the string    url_to_sign = url.path + "?" + url.query    # Decode the private key into its binary format    # We need to decode the URL-encoded private key    decoded_key = base64.urlsafe_b64decode(secret)    # Create a signature using the private key and the URL-encoded    # string using HMAC SHA1. This signature will be binary.    signature = hmac.new(decoded_key, str.encode(url_to_sign), hashlib.sha1)    # Encode the binary signature into base64 for use within a URL    encoded_signature = base64.urlsafe_b64encode(signature.digest())    original_url = url.scheme + "://" + url.netloc + url.path + "?" + url.query    # Return signed URL    return original_url + "&signature=" + encoded_signature.decode()
GOOGLE_API_KEY = 'AIzaSyD1...'GOOGLE_MAPS_STATIC_URL_SIGNINING_SECRET = 'abc...'url = f"https://maps.googleapis.com/maps/api/staticmap?center=35.01856,135.68077&markers=35.01856,135.68077&zoom=16&size=370x300&key={GOOGLE_API_KEY}&sensor=false"# the final url will have a 'signature' parameterurl = signed_url(url, GOOGLE_MAPS_STATIC_URL_SIGNINING_SECRET)

References:

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.