Client ID リクエストの署名

注: 現在、Google Maps Platform プレミアム プランは、新規お申し込みまたは新規お客様のご利用を受け付けていません。

デジタル署名

デジタル署名の仕組み

デジタル署名は、Google Cloud Console で取得できる URL 署名シークレットまたは暗号鍵を使用して生成されます。このシークレットは基本的に秘密鍵であり、お客様と Google との間でのみ共有され、お客様のクライアント ID に固有の情報です。

署名プロセスでは、暗号化アルゴリズムを使用して URL と共有シークレットを結合し、一意の署名が生成されます。この一意の署名により、お客様のクライアント ID を使用してリクエストを生成するサイトは、いずれも許可されたサイトであることがわかります。

リクエストに署名する

リクエストの署名は、次の手順で構成されます。

ステップ 1: URL 署名シークレットを取得する

プロジェクトの URL 署名シークレットを取得するには:

  1. Cloud Console の [クライアント ID] ページに移動します。
  2. [キー] フィールドに、現在のクライアント ID の URL 署名シークレットが含まれています。

クライアント ID の URL 署名シークレットを再生成する必要がある場合は、サポートにお問い合わせください。

ステップ 2: 署名なしのリクエストを作成する

署名なしのリクエスト URL を作成します。

client パラメータには、クライアント ID も必ず含めてください。例:

https://maps.googleapis.com/maps/api/staticmap?center=40.714%2c%20-73.998&zoom=12&size=400x400&client=YOUR_CLIENT_ID

署名付きリクエストを生成する

トラブルシューティングの目的で、今すぐ URL に署名ウィジェットを使用してデジタル署名を自動的に生成できます。

動的に生成されるリクエストでは、サーバー側の署名が必要です。サーバー側の署名にはいくつかの追加の中間手順が必要です。

どちらの場合も、末尾に signature パラメータが付加されたリクエスト URL になります。例:

https://maps.googleapis.com/maps/api/staticmap?center=40.714%2c%20-73.998&zoom=12&size=400x400&client=YOUR_CLIENT_ID
&signature=BASE64_SIGNATURE
「今すぐ URL に署名」ウィジェットを使用する

クライアント ID でデジタル署名を生成するには、以下の [今すぐ URL に署名する] ウィジェットを使用します。

  1. ステップ 1: URL 署名シークレットを取得するの説明に従って、クライアント ID の URL 署名シークレットを取得します。
  2. [URL] フィールドに、ステップ 2: 署名なしのリクエストを作成するで作成した署名なしのリクエスト URL を貼り付けます。
  3. [URL 署名シークレット] に、ステップ 2 の URL 署名シークレットを貼り付けます。
    デジタル署名は、署名なしのリクエスト URL と署名シークレットに基づいて生成され、元の URL に追加されます。
  4. 表示される [署名付き URL] フィールドには、デジタル署名された URL が含まれます。必ずコピーを作成してください。
サーバー側でデジタル署名を生成する

[今すぐ URL に署名] ウィジェットとは異なり、サーバー側でデジタル署名を生成する場合は、追加の操作を行う必要があります。

  1. URL のプロトコル スキームとホスト部分を削除し、パスとクエリのみを残します。

  2. /maps/api/staticmap?center=40.714%2c%20-73.998&zoom=12&size=400x400&client=YOUR_CLIENT_ID
    
  3. 表示される URL 署名シークレットは、URL 用に変更された Base64 でエンコードされます。

    ほとんどの暗号ライブラリでは、鍵が RAW バイト形式になっているため、署名する前に URL 署名シークレットを元の未加工の形式にデコードする作業が必要になる可能性があります。

  4. HMAC-SHA1 を使用して上記のリクエストに署名します。
  5. ほとんどの暗号ライブラリでは、RAW バイト形式で署名が生成されるため、URL 用に変更された Base64 を使用して、生成されたバイナリ署名を URL 内で渡すことのできるものに変換する必要があります。

  6. Base64 でエンコードされた署名を、signature パラメータの元の未署名リクエスト URL に追加します。例:

    https://maps.googleapis.com/maps/api/staticmap?center=40.714%2c%20-73.998&zoom=12&size=400x400&client=YOUR_CLIENT_ID
    &signature=BASE64_SIGNATURE

サーバー側のコードを使用して URL 署名を実装する方法については、以下の URL 署名のサンプルコードをご覧ください。

URL 署名のサンプルコード

以下のセクションでは、サーバー側のコードを使用して URL 署名を実装する方法を説明します。URL 署名シークレットをユーザーに知られないようにするため、URL は常にサーバー側で署名してください。

Python

次の例では、標準の Python ライブラリを使用して URL に署名します(サンプルコードをダウンロード)。

#!/usr/bin/python
# -*- coding: utf-8 -*-
""" Signs a URL using a URL signing secret """

import hashlib
import hmac
import base64
import urllib.parse as urlparse

def sign_url(input_url=None, secret=None):
    """ Sign a request URL with a URL signing secret.
      Usage:
      from urlsigner import sign_url
      signed_url = sign_url(input_url=my_url, secret=SECRET)
      Args:
      input_url - The URL to sign
      secret    - Your URL signing secret
      Returns:
      The signed request URL
  """

    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()

if __name__ == "__main__":
    input_url = input("URL to Sign: ")
    secret = input("URL signing secret: ")
    print("Signed URL: " + sign_url(input_url, secret))

Java

次の例では、JDK 1.8 以降で利用可能な java.util.Base64 クラスを使用します。これより古いバージョンでは、Apache Commons などを使用する必要があります(サンプルコードをダウンロード)。

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;  // JDK 1.8 only - older versions may need to use Apache Commons or similar.
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class UrlSigner {

  // Note: Generally, you should store your private key someplace safe
  // and read them into your code

  private static String keyString = "YOUR_PRIVATE_KEY";

  // The URL shown in these examples is a static URL which should already
  // be URL-encoded. In practice, you will likely have code
  // which assembles your URL from user or web service input
  // and plugs those values into its parameters.
  private static String urlString = "YOUR_URL_TO_SIGN";

  // This variable stores the binary key, which is computed from the string (Base64) key
  private static byte[] key;

  public static void main(String[] args) throws IOException,
    InvalidKeyException, NoSuchAlgorithmException, URISyntaxException {

    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

    String inputUrl, inputKey = null;

    // For testing purposes, allow user input for the URL.
    // If no input is entered, use the static URL defined above.
    System.out.println("Enter the URL (must be URL-encoded) to sign: ");
    inputUrl = input.readLine();
    if (inputUrl.equals("")) {
      inputUrl = urlString;
    }

    // Convert the string to a URL so we can parse it
    URL url = new URL(inputUrl);

    // For testing purposes, allow user input for the private key.
    // If no input is entered, use the static key defined above.
    System.out.println("Enter the Private key to sign the URL: ");
    inputKey = input.readLine();
    if (inputKey.equals("")) {
      inputKey = keyString;
    }

    UrlSigner signer = new UrlSigner(inputKey);
    String request = signer.signRequest(url.getPath(),url.getQuery());

    System.out.println("Signed URL :" + url.getProtocol() + "://" + url.getHost() + request);
  }

  public UrlSigner(String keyString) throws IOException {
    // Convert the key from 'web safe' base 64 to binary
    keyString = keyString.replace('-', '+');
    keyString = keyString.replace('_', '/');
    System.out.println("Key: " + keyString);
    // Base64 is JDK 1.8 only - older versions may need to use Apache Commons or similar.
    this.key = Base64.getDecoder().decode(keyString);
  }

  public String signRequest(String path, String query) throws NoSuchAlgorithmException,
    InvalidKeyException, UnsupportedEncodingException, URISyntaxException {

    // Retrieve the proper URL components to sign
    String resource = path + '?' + query;

    // Get an HMAC-SHA1 signing key from the raw key bytes
    SecretKeySpec sha1Key = new SecretKeySpec(key, "HmacSHA1");

    // Get an HMAC-SHA1 Mac instance and initialize it with the HMAC-SHA1 key
    Mac mac = Mac.getInstance("HmacSHA1");
    mac.init(sha1Key);

    // compute the binary signature for the request
    byte[] sigBytes = mac.doFinal(resource.getBytes());

    // base 64 encode the binary signature
    // Base64 is JDK 1.8 only - older versions may need to use Apache Commons or similar.
    String signature = Base64.getEncoder().encodeToString(sigBytes);

    // convert the signature to 'web safe' base 64
    signature = signature.replace('+', '-');
    signature = signature.replace('/', '_');

    return resource + "&signature=" + signature;
  }
}

Node JS

次の例では、ネイティブの Node モジュールを使用して URL に署名します(サンプルコードをダウンロード)。

'use strict'

const crypto = require('crypto');
const url = require('url');

/**
 * Convert from 'web safe' base64 to true base64.
 *
 * @param  {string} safeEncodedString The code you want to translate
 *                                    from a web safe form.
 * @return {string}
 */
function removeWebSafe(safeEncodedString) {
  return safeEncodedString.replace(/-/g, '+').replace(/_/g, '/');
}

/**
 * Convert from true base64 to 'web safe' base64
 *
 * @param  {string} encodedString The code you want to translate to a
 *                                web safe form.
 * @return {string}
 */
function makeWebSafe(encodedString) {
  return encodedString.replace(/\+/g, '-').replace(/\//g, '_');
}

/**
 * Takes a base64 code and decodes it.
 *
 * @param  {string} code The encoded data.
 * @return {string}
 */
function decodeBase64Hash(code) {
  // "new Buffer(...)" is deprecated. Use Buffer.from if it exists.
  return Buffer.from ? Buffer.from(code, 'base64') : new Buffer(code, 'base64');
}

/**
 * Takes a key and signs the data with it.
 *
 * @param  {string} key  Your unique secret key.
 * @param  {string} data The url to sign.
 * @return {string}
 */
function encodeBase64Hash(key, data) {
  return crypto.createHmac('sha1', key).update(data).digest('base64');
}

/**
 * Sign a URL using a secret key.
 *
 * @param  {string} path   The url you want to sign.
 * @param  {string} secret Your unique secret key.
 * @return {string}
 */
function sign(path, secret) {
  const uri = url.parse(path);
  const safeSecret = decodeBase64Hash(removeWebSafe(secret));
  const hashedSignature = makeWebSafe(encodeBase64Hash(safeSecret, uri.path));
  return url.format(uri) + '&signature=' + hashedSignature;
}

C#

次の例では、デフォルトの System.Security.Cryptography ライブラリを使用して URL リクエストに署名します。URL セーフ バージョンを実装するには、デフォルトの Base64 エンコーディングを変換する必要があります(サンプルコードをダウンロード)。

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace SignUrl {

  public struct GoogleSignedUrl {

    public static string Sign(string url, string keyString) {
      ASCIIEncoding encoding = new ASCIIEncoding();

      // converting key to bytes will throw an exception, need to replace '-' and '_' characters first.
      string usablePrivateKey = keyString.Replace("-", "+").Replace("_", "/");
      byte[] privateKeyBytes = Convert.FromBase64String(usablePrivateKey);

      Uri uri = new Uri(url);
      byte[] encodedPathAndQueryBytes = encoding.GetBytes(uri.LocalPath + uri.Query);

      // compute the hash
      HMACSHA1 algorithm = new HMACSHA1(privateKeyBytes);
      byte[] hash = algorithm.ComputeHash(encodedPathAndQueryBytes);

      // convert the bytes to string and make url-safe by replacing '+' and '/' characters
      string signature = Convert.ToBase64String(hash).Replace("+", "-").Replace("/", "_");

      // Add the signature to the existing URI.
      return uri.Scheme+"://"+uri.Host+uri.LocalPath + uri.Query +"&signature=" + signature;
    }
  }

  class Program {

    static void Main() {

      // Note: Generally, you should store your private key someplace safe
      // and read them into your code

      const string keyString = "YOUR_PRIVATE_KEY";

      // The URL shown in these examples is a static URL which should already
      // be URL-encoded. In practice, you will likely have code
      // which assembles your URL from user or web service input
      // and plugs those values into its parameters.
      const  string urlString = "YOUR_URL_TO_SIGN";

      string inputUrl = null;
      string inputKey = null;

      Console.WriteLine("Enter the URL (must be URL-encoded) to sign: ");
      inputUrl = Console.ReadLine();
      if (inputUrl.Length == 0) {
        inputUrl = urlString;
      }

      Console.WriteLine("Enter the Private key to sign the URL: ");
      inputKey = Console.ReadLine();
      if (inputKey.Length == 0) {
        inputKey = keyString;
      }

      Console.WriteLine(GoogleSignedUrl.Sign(inputUrl,inputKey));
    }
  }
}

その他の言語のサンプルコード

その他の言語のサンプルコードは、URL 署名プロジェクトで入手できます。

認証の問題のトラブルシューティング

リクエストの形式が正しくない場合や、署名が無効な場合は、Directions API から HTTP 403 (Forbidden) エラーが返されます。

この問題をトラブルシューティングするには、リクエスト URL をコピーし、signature クエリ パラメータを削除した後、上記の「今すぐ URL に署名」ウィジェットを使用するの手順に従って、有効な署名を再生成します。