Assinatura da solicitação do ID do cliente

Observação: o Plano Premium da Plataforma Google Maps não está mais disponível para inscrições ou novos clientes.

Assinaturas digitais

Como funcionam as assinaturas digitais

As assinaturas digitais são geradas usando uma Chave secreta de assinatura do URL ou uma chave criptográfica disponível no console do Google Cloud. Ela é essencialmente uma chave privada, compartilhada somente entre você e o Google, e pertence exclusivamente ao seu ID de cliente.

O processo de assinatura usa um algoritmo de criptografia para combinar o URL e a chave secreta compartilhada. Quando você usa a assinatura exclusiva resultante, nossos servidores verificam se os sites que gerarem solicitações usando seu ID de cliente têm autorização para isso.

Assinar suas solicitações

Veja a seguir as etapas para assinar suas solicitações:

Etapa 1: gerar a Chave secreta de assinatura do URL

Para ver a Chave secreta de assinatura do URL do projeto, siga estas etapas:

  1. Acesse a página do ID do cliente no Console do Cloud.
  2. No campo Chave, você encontra a Chave secreta de assinatura do URL do ID do cliente.

Se precisar gerar novamente essa chave, entre em contato com o suporte.

Etapa 2: criar solicitação sem assinatura

Os caracteres não listados na tabela abaixo precisam ser codificados para uso em URL:

Resumo de caracteres válidos para URLs
ConjuntoCaracteresUso em URLs
Alfanuméricos a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 Strings de texto, uso do esquema (http), porta (8080) etc.
Não reservados - _ . ~ Strings de texto
Reservados ! * ' ( ) ; : @ & = + $ , / ? % # [ ] Caracteres de controle e/ou strings de texto

O mesmo vale para todos os caracteres no conjunto Reservado, se eles forem transferidos dentro de uma string de texto. Para mais informações, consulte Caracteres especiais.

Gere o URL de solicitação sem assinatura.

Inclua também o ID do cliente no parâmetro client. Exemplo:

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

Gerar a solicitação assinada

Para solucionar problemas, você pode gerar uma assinatura digital automaticamente usando o widget Assinar URL agora.

Para solicitações geradas dinamicamente, você precisa da assinatura do lado do servidor, que requer mais algumas etapas intermediárias.

De qualquer forma, haverá um URL de solicitação com um parâmetro signature anexado ao final. Exemplo:

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
  1. Remova o esquema do protocolo e as partes do host do URL, deixando apenas o caminho e a consulta:

  2. /maps/api/staticmap?center=40.714%2c%20-73.998&zoom=12&size=400x400&client=YOUR_CLIENT_ID
    
  3. A Chave secreta de assinatura do URL exibida é codificada em um Base64 modificado para URLs.

    Como a maioria das bibliotecas criptográficas exige que a chave esteja no formato de bytes brutos, você provavelmente vai precisar decodificar a Chave secreta de assinatura do URL no formato bruto original antes de assinar.

  4. Assine a solicitação com as partes removidas acima usando HMAC-SHA1.
  5. Como a maioria das bibliotecas criptográficas gera uma assinatura no formato de byte bruto, você precisa converter a assinatura binária resultante usando o método Base64 modificado para que os URLs o convertam em algo que possa ser transmitido dentro do URL.

  6. Anexe a assinatura codificada com Base64 ao URL original da solicitação não assinada no parâmetro signature. Exemplo:

    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

Se quiser exemplos de como implementar a assinatura de URL usando o código do lado do servidor, consulte Exemplo de código para assinatura de URL abaixo.

Exemplo de código para assinatura de URL

As seções abaixo mostram como implementar a assinatura de URL usando o código do lado do servidor. Os URLs sempre precisam ser assinados no servidor para evitar a exposição da Chave secreta de assinatura do URL aos usuários.

Python

O exemplo abaixo usa bibliotecas Python padrão para assinar um URL. Faça o download do código (link em inglês).

#!/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

O exemplo abaixo usa a classe java.util.Base64 disponível desde o JDK 1.8. Talvez as versões mais antigas precisem usar o Apache Commons ou similar. Faça o download do código (link em inglês).

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

O exemplo abaixo usa módulos nativos do Node para assinar um URL. Faça o download do código (link em inglês).

'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#

No exemplo abaixo, a biblioteca padrão System.Security.Cryptography é usada para assinar uma solicitação de URL. É preciso converter a codificação Base64 padrão para implementar uma versão compatível com URL. Faça o download do código (link em inglês).

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));
    }
  }
}

Exemplos em outras linguagens

Confira outros exemplos de linguagens no projeto url-signing (link em inglês).

Solução de problemas

Se a solicitação for corrompida ou fornecer uma assinatura inválida, a API vai retornar um erro HTTP 403 (Forbidden).

Para solucionar o problema, copie o URL da solicitação, remova o parâmetro de consulta signature e gere novamente uma assinatura válida seguindo as instruções abaixo:

Para gerar uma assinatura digital com seu ID do cliente usando o widget Assinar URL agora, faça o seguinte:

  1. Busque a chave secreta de assinatura do URL do ID do cliente, conforme descrito na Etapa 1: gerar a Chave secreta de assinatura do URL.
  2. No campo URL, cole o URL da Etapa 2: criar solicitação sem assinatura.
  3. No campo Chave secreta de assinatura do URL, cole a chave da etapa 2.
    Uma assinatura digital é gerada com base no URL de solicitação sem assinatura e na chave secreta de assinatura, além de ser anexada ao URL original.
  4. O URL assinado digitalmente vai aparecer no campo Seu URL assinado.