Processus de signature V4 avec votre propre programme

Cette page décrit un algorithme vous permettant de mettre en œuvre le processus de signature V4 afin de pouvoir créer des URL signées par une clé RSA Cloud Storage dans votre propre workflow, en utilisant le langage de programmation de votre choix. Les URL signées offrent un accès en lecture ou en écriture limité dans le temps à une ressource Cloud Storage spécifique. Toute personne disposant de l'URL signée peut l'utiliser tant qu'elle est active, qu'elle possède ou non un compte Google.

Pour apprendre à utiliser les outils Cloud Storage afin de créer plus facilement des URL signées par une clé RSA Cloud Storage, consultez la page Processus de signature V4 avec les outils Cloud Storage. Pour en savoir plus sur les URL signées, consultez la page Présentation des URL signées.

Prérequis

Avant de créer un programme qui met en œuvre le processus de signature V4, vous devez effectuer les opérations suivantes :

  1. Générez une nouvelle clé privée ou utilisez une clé privée existante pour un compte de service. Elle peut être au format JSON ou PKCS12.

    Pour en savoir plus sur les clés privées et les comptes de service, consultez la page Comptes de service.

  2. Accordez au compte de service des autorisations suffisantes pour qu'il puisse effectuer la requête adressée par l'URL signée.

    Par exemple, si l'URL signée autorise un utilisateur à télécharger un objet, le compte de service doit disposer de l'autorisation storage.objects.get sur cet objet.

Algorithme de signature des URL

Votre programme doit inclure les étapes suivantes :

  1. Créez la requête canonique sous forme de chaîne. La requête canonique définit les éléments que les utilisateurs doivent inclure dans leur requête lorsqu'ils utilisent votre URL signée.

    La requête canonique doit avoir la structure suivante et utiliser des sauts de ligne entre chaque élément :

    HTTP_VERB
    PATH_TO_RESOURCE
    CANONICAL_QUERY_STRING
    CANONICAL_HEADERS
    
    SIGNED_HEADERS
    UNSIGNED-PAYLOAD

    La requête canonique comprend les composants suivants :

    • HTTP_VERB : verbe HTTP à utiliser avec l'URL signée.

      Pour obtenir la liste des valeurs autorisées, consultez la section Verbes HTTP.

    • PATH_TO_RESOURCE : chemin d'accès à la ressource, commençant après le nom de l'hôte. Lorsque vous définissez ce chemin, vous devez effectuer un encodage-pourcent des caractères réservés suivants : ?=!#$&'()*+,:;@[]."

    • CANONICAL_QUERY_STRING : paramètres de chaîne de requête que les requêtes utilisant l'URL signée doivent inclure. Ajoutez des paramètres de chaîne de requête par ordre alphabétique et séparez-les à l'aide du caractère &.

    • CANONICAL_HEADERS : paires nom:valeur pour les en-têtes que les requêtes utilisant l'URL signée doivent inclure, y compris les en-têtes d'extension. Ajoutez des en-têtes par ordre alphabétique et séparez-les à l'aide du caractère \n.

    • SIGNED_HEADERS : noms d'en-tête des éléments CANONICAL_HEADERS, séparés par le caractère ;.

    • UNSIGNED-PAYLOAD : cette chaîne doit apparaître sur la dernière ligne de la requête canonique.

  2. Utilisez une fonction de hachage SHA-256 pour créer une valeur de hachage à encodage hexadécimal de la requête canonique.

    Votre langage de programmation doit disposer d'une bibliothèque pour créer des hachages SHA-256. Voici un exemple de valeur de hachage :

    436b7ce722d03b17d3f790255dd57904f7ed61c02ac5127a0ca8063877e4e42c
  3. Créez la chaîne à signer.

    La chaîne à signer doit avoir la structure suivante et utiliser des sauts de ligne entre chaque élément :

    SIGNING_ALGORITHM
    CURRENT_DATETIME
    CREDENTIAL_SCOPE
    HASHED_CANONICAL_REQUEST

    La chaîne à signer comprend les composants suivants :

    • SIGNING_ALGORITHM : il doit s'agir de GOOG4-RSA-SHA256.

    • CURRENT_DATETIME : date et heure actuelles, au format de base ISO 8601 YYYYMMDD'T'HHMMSS'Z'.

    • CREDENTIAL_SCOPE : champ d'application des identifiants de la requête pour la signature de la chaîne à signer.

    • HASHED_CANONICAL_REQUEST : hachage SHA-256 à encodage hexadécimal de la requête canonique, que vous avez créée à l'étape précédente.

  4. Signez la chaîne à l'aide d'une signature RSA avec un hachage SHA-256. Le résultat de cette signature est votre signature de requête.

    Votre langage de programmation doit disposer d'une bibliothèque pour effectuer des signatures RSA. Dans une application Google App Engine, vous pouvez utiliser le service App Identity d'App Engine pour signer votre chaîne.

  5. Créez l'URL signée à l'aide de la concaténation suivante :

    HOSTNAME + PATH_TO_RESOURCE + "?" + CANONICAL_QUERY_STRING + "&X-Goog-Signature=" + REQUEST_SIGNATURE

    L'URL signée comprend les composants suivants :

    • HOSTNAME : il doit s'agir de https://storage.googleapis.com.

    • PATH_TO_RESOURCE : il doit correspondre à la valeur que vous avez utilisée lors de la création de la requête canonique.

    • CANONICAL_QUERY_STRING : il doit correspondre aux valeurs que vous avez utilisées lors de la création de la requête canonique.

    • REQUEST_SIGNATURE : résultat de l'utilisation d'une signature RSA à l'étape précédente.

    Voici un exemple d'URL générée :

    https://storage.googleapis.com/example-bucket/cat.jpeg?x-goog-algorithm=GOOG4-
    RSA-SHA256&X-Goog-Credential=example%40example-project.iam.gserviceaccount.com
    %2F20181026%2Fus%2Fstorage%2Fgoog4_request&X-Goog-Date=20181026T211942Z&X-Goog
    -expires=3600&X-Goog-Signedheaders=host&X-Goog-Signature=2d2a6f5055eb004b8690b
    9479883292ae7450cdc15f17d7f99bc49b916f9e7429106ed7e5858ae6b4ab0bbbdb1a8ccc364d
    ad3a0da2caebd30887a70c5b2569d089ceb8afbde3eed4dff5086f0db5483998c175980991fe89
    9fbd2cd8cb813b00165e8d56e0a8aa7b3d7a12ee1baa8400611040f05b50a1a8eab5ba223fe137
    5747748de950ec7a4dc50f8382a6ffd4994ac42498d7daa703d9a414d4475154d0e7edaa92d4f2
    507d92c1f7e8efa7cab64df68b5df48575b9259d8d0bdb5dc752bdf07bd162d98ff2924f2e4a26
    fa6b3cede73ad5333c47d146a21c2ab2d97115986a12c68ff37346d6c2ca83e56b8ec8ad956327
    10b489b75c35697d781c38e

Exemple de programme en Python

L'exemple suivant montre une mise en œuvre de l'algorithme pour la signature d'URL. L'exemple utilise le langage de programmation Python :

import binascii
import collections
import datetime
import hashlib
import sys

# pip install six
from six.moves.urllib.parse import quote

# pip install google-auth
from google.oauth2 import service_account

def generate_signed_url(service_account_file, bucket_name, object_name,
                        expiration, http_method='GET', query_parameters=None,
                        headers=None):

    if expiration > 604800:
        print('Expiration Time can\'t be longer than 604800 seconds (7 days).')
        sys.exit(1)

    escaped_object_name = quote(object_name, safe='')
    canonical_uri = '/{}/{}'.format(bucket_name, escaped_object_name)

    datetime_now = datetime.datetime.utcnow()
    request_timestamp = datetime_now.strftime('%Y%m%dT%H%M%SZ')
    datestamp = datetime_now.strftime('%Y%m%d')

    google_credentials = service_account.Credentials.from_service_account_file(
        service_account_file)
    client_email = google_credentials.service_account_email
    credential_scope = '{}/auto/storage/goog4_request'.format(datestamp)
    credential = '{}/{}'.format(client_email, credential_scope)

    if headers is None:
        headers = dict()
    headers['host'] = 'storage.googleapis.com'

    canonical_headers = ''
    ordered_headers = collections.OrderedDict(sorted(headers.items()))
    for k, v in ordered_headers.items():
        lower_k = str(k).lower()
        strip_v = str(v).lower()
        canonical_headers += '{}:{}\n'.format(lower_k, strip_v)

    signed_headers = ''
    for k, _ in ordered_headers.items():
        lower_k = str(k).lower()
        signed_headers += '{};'.format(lower_k)
    signed_headers = signed_headers[:-1]  # remove trailing ';'

    if query_parameters is None:
        query_parameters = dict()
    query_parameters['X-Goog-Algorithm'] = 'GOOG4-RSA-SHA256'
    query_parameters['X-Goog-Credential'] = credential
    query_parameters['X-Goog-Date'] = request_timestamp
    query_parameters['X-Goog-Expires'] = expiration
    query_parameters['X-Goog-SignedHeaders'] = signed_headers

    canonical_query_string = ''
    ordered_query_parameters = collections.OrderedDict(
        sorted(query_parameters.items()))
    for k, v in ordered_query_parameters.items():
        encoded_k = quote(str(k), safe='')
        encoded_v = quote(str(v), safe='')
        canonical_query_string += '{}={}&'.format(encoded_k, encoded_v)
    canonical_query_string = canonical_query_string[:-1]  # remove trailing ';'

    canonical_request = '\n'.join([http_method,
                                   canonical_uri,
                                   canonical_query_string,
                                   canonical_headers,
                                   signed_headers,
                                   'UNSIGNED-PAYLOAD'])

    canonical_request_hash = hashlib.sha256(
        canonical_request.encode()).hexdigest()

    string_to_sign = '\n'.join(['GOOG4-RSA-SHA256',
                                request_timestamp,
                                credential_scope,
                                canonical_request_hash])

    signature = binascii.hexlify(
        google_credentials.signer.sign(string_to_sign)
    ).decode()

    host_name = 'https://storage.googleapis.com'
    signed_url = '{}{}?{}&X-Goog-Signature={}'.format(host_name, canonical_uri,
                                                      canonical_query_string,
                                                      signature)
    return signed_url
Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Besoin d'aide ? Consultez notre page d'assistance.