인증 및 승인

이 페이지는 이전 Maps APIs for Work 또는 Maps API for Business 라이선스가 있는 고객만을 위한 것입니다. 이 페이지는 2016년 1월에 출시된 새 Google Maps API 프리미엄 플랜가 있는 고객에게는 적용되지 않습니다.

클라이언트 ID 및 서명

Google Maps APIs for Work 라이선스로 Google Maps APIs 웹 서비스를 사용 중인 경우, API 키 대신 클라이언트 ID와 고유 디지털 서명의 두 인증 매개변수가 필요합니다.

무료 API 웹 서비스를 Google Maps APIs for Work 구현으로 전환 중인 경우에는 key 매개변수를 요청에서 제거해야 합니다. 클라이언트 ID와 키로 동시에 생성된 요청은 Google Maps APIs 웹 서비스가 거부합니다.

클라이언트 ID 및 서명

Google Maps APIs for Work 라이선스를 구입하면, Google로부터 클라이언트 ID개인 암호화 키가 포함된 환영 이메일을 받게 됩니다.

  • 클라이언트 ID는 Google Maps APIs for Work의 특별한 기능에 액세스하는 데 사용됩니다. API 라이브러리나 서비스에 액세스할 때 클라이언트 ID를 제공해야 합니다. 모든 클라이언트 ID는 gme- 접두사로 시작합니다. 클라이언트 ID를 client 매개변수의 값으로 전달합니다.

  • 고유 디지털 서명은 개인 암호화 키를 사용하여 생성됩니다. 이 서명을 signature 매개변수의 값으로 전달합니다. 서명 생성에 대한 자세한 내용은 아래의 디지털 서명 섹션을 참조하세요.

다음은 Google Maps Directions API의 예시입니다.

    https://maps.googleapis.com/maps/api/directions/json
      ?origin=Toronto
      &destination=Montreal
      &client=gme-YOUR_CLIENT_ID
      &signature=YOUR_URL_SIGNATURE

클라이언트 ID나 개인 암호화 키를 분실한 경우 찾으려면 Google Cloud Support Portal에 로그인하고 페이지 왼쪽의 링크에서 Maps: Manage Client ID를 클릭합니다.

보고서용 매개변수(선택 항목)

인증 매개변수 외에도 Google Maps APIs for Work 요청에는 다음과 같은 매개변수가 선택 항목으로 사용됩니다.

  • channel은 추가적인 보고 세부정보를 제공하는 데 사용되며, 보고서에서 다른 채널을 별도로 분류합니다. Google Maps APIs for Work 웹 서비스 할당량 및 보고 문서의 채널 보고서 섹션을 참조하세요.

디지털 서명

Google Maps APIs for Work에 의한 Web Service API 요청에는 디지털 signature가 필요하며, 이 서명은 환영 이메일에서 제공되는 개인 암호화 키를 사용하여 생성됩니다.

서명 프로세스는 암호화 알고리즘을 사용하여 URL과 키를 서로 조합합니다. 여러분의 클라이언트 ID를 사용해 요청을 생성하는 사이트가 있을 경우, Google 서버가 이 고유 서명을 통해 해당 사이트에 그러한 권한이 있는지 확인할 수 있습니다. 또한 서명은 URL마다 고유하며, 여러분의 클라이언트 ID를 사용하는 요청을 수정하려면 새 서명을 생성해야 합니다.

개인 암호화 키

개인 암호화 URL 서명 키는 클라이언트 ID로 발급되며 여러분과 Google 사이의 "비밀 공유 키"입니다. 이 서명 키는 여러분만의 것이며 클라이언트 ID에 고유한 키입니다. 이러한 이유로, 서명 키를 안전하게 보관해야 합니다. 이 키는 어떠한 요청 안에 넣어 전달되거나, 웹사이트에 저장되거나, 공개 포럼에 게시되어서도 안됩니다. 이 서명 키를 획득한 사람이 여러분의 ID를 사용하여 요청을 스푸핑할 수 있습니다.

참고: 이 개인 암호화 서명 키는 Google API Console에 의해 발급된 API 키와 동일한 것이 아닙니다.

개인 암호화 키를 분실한 경우 찾으려면 Google Cloud Support Portal에 로그인하고 Maps: Manage Client ID를 클릭합니다.

디지털 서명 생성

잘못된 서명으로 Google Maps APIs 웹 서비스에 액세스를 시도하면 HTTP 403 (Forbidden) 오류가 발생합니다. URL 서명을 사용하도록 애플리케이션을 변환할 때, 올바른 요청이 시작되는지 확인하기 위해 서명을 테스트하세요. 먼저 원본 URL이 올바른지 테스트하고 또한 올바른 서명이 생성되는지 여부를 테스트해야 합니다.

다음 단계에 따라 요청에 사용할 디지털 서명을 생성합니다.

  1. 서명이 없는 요청 URL을 생성하고, client 매개변수를 포함해야 합니다. 참고로, 모든 비표준 문자는 URL 인코딩되어야 합니다. 예를 들어, Directions API의 경우 다음과 같이 URL을 구성합니다.

    https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&client=clientID

    참고: 모든 Google 서비스는 (암시적으로 ASCII를 포함하는) UTF-8 문자 인코딩을 요구합니다. 다른 문자 집합을 사용하여 실행되는 애플리케이션의 경우, 반드시 UTF-8로 URL을 생성하고 올바로 URL 인코딩하세요.

  2. 요청에서 도메인 부분을 떼어내고 path와 query만 남겨둡니다. 예를 들어, Directions API의 경우:

    /maps/api/directions/json?origin=Toronto&destination=Montreal&client=clientID

  3. 수정된 URL용 Base64로 인코딩된 개인 키를 가져오고, HMAC-SHA1 알고리즘을 사용하여 위의 URL에 서명합니다. 이 키를 원래의 바이너리 형식으로 디코딩해야 할 수도 있습니다. 대부분의 암호 라이브러리에서 최종 서명이 바이너리 형식이라는 점에 유의하세요.

    참고: 수정된 URL용 Base64는 표준 Base64의 +/ 문자를 각각 -_로 대체하므로, 이러한 Base64 서명에는 더 이상 URL 인코딩이 필요하지 않습니다.

  4. 수정된 URL용 Base64를 사용해서 최종 바이너리 서명을 인코딩하고, 이 서명을 URL 내에서 전달할 수 있는 형식으로 변환합니다.

  5. 이 서명을 signature 매개변수 내의 URL 내에 첨부합니다. 예를 들어, Directions API의 경우:

    https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&client=clientID&signature=base64signature

서버측 코드를 사용하여 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 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, 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

if __name__ == "__main__":
  input_url = raw_input("URL to Sign: ")
  secret = raw_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;
  }
}

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과 개인 키를 테스트하여 올바른 서명이 생성되는지 여부를 확인할 수 있습니다. 참고로, 이 개인 키는 오직 테스트 용도로만 사용되며 Google 서비스에 의해 확인되지 않습니다.

  • URL: https://maps.googleapis.com/maps/api/geocode/json?address=New+York&client=clientID
  • 개인 키: vNIXE0xscrmjlyV-12Nj_BvUPaw=
  • 서명할 URL 부분: /maps/api/geocode/json?address=New+York&client=clientID
  • 서명: chaRF2hTJKOScPr-RQCEhZbSzIE=
  • 서명된 전체 URL: https://maps.googleapis.com/maps/api/geocode/json?address=New+York&client=clientID&signature=chaRF2hTJKOScPr-RQCEhZbSzIE=

다른 언어로 구현된 예시

URL 서명 프로젝트에서 다른 언어로 구현된 예시를 확인할 수 있습니다.

인증 문제 해결

요청이 잘못되었거나 유효하지 않은 서명을 제공하면 Web Service API가 HTTP 403 (Forbidden) 오류를 반환합니다.

개별 URL의 문제를 해결하기 위해 URL Signing Debugger를 사용할 수 있습니다. 이 도구를 사용하면 애플리케이션이 생성한 URL과 서명의 유효성을 신속하게 검사할 수 있습니다.

또는 Google Maps APIs for Work 고객이 Google Cloud Support Portal에 로그인하고 Resources > Google Maps 온라인 도구 > URL Signing Debugger for Web Service and Image APIs를 선택하여 개별 URL의 문제를 해결할 수 있습니다.