V4-Signaturprozess mit Ihrem eigenen Programm

Auf dieser Seite wird ein Algorithmus zum Implementieren des V4-Signaturprozesses beschrieben, mit dem Sie in Ihrem eigenen Workflow URLs erstellen können, die mit Cloud Storage-RSA-Schlüsseln signiert sind. Sie nutzen dazu eine von Ihnen gewählte Programmiersprache. Signierte URLs bieten zeitlich begrenzten Lese- oder Schreibzugriff auf eine bestimmte Cloud Storage-Ressource. Jede Person im Besitz einer signierten URL kann diese verwenden, während sie aktiv ist. Dies gilt unabhängig davon, ob die Person ein Google-Konto hat.

Informationen zur Verwendung von Cloud Storage-Tools für das einfache Erstellen von URLs, die mit Cloud Storage-RSA-Schlüsseln signiert sind, finden Sie unter V4-Signaturprozess mit Cloud Storage-Tools. Weitere Informationen zu signierten URLs finden Sie unter Übersicht über signierte URLs.

Voraussetzungen

Bevor Sie ein Programm erstellen, das den V4-Signaturprozess implementiert, führen Sie folgende Schritte aus:

  1. Generieren Sie einen neuen privaten Schlüssel oder nutzen Sie einen vorhandenen privaten Schlüssel für ein Dienstkonto. Der Schlüssel kann entweder im JSON- oder im PKCS12-Format vorliegen.

    Weitere Informationen zu privaten Schlüsseln und Dienstkonten finden Sie unter Dienstkonten.

  2. Erteilen Sie dem Dienstkonto ausreichende Berechtigungen, um die Anfrage der signierten URL ausführen zu können.

    Wenn die signierte URL beispielsweise einem Nutzer das Herunterladen eines Objekts ermöglicht, muss das Dienstkonto die Berechtigung storage.objects.get für das Objekt haben.

Algorithmus zum Signieren von URLs

Das Programm sollte folgende Schritte umfassen:

  1. Erstellen der kanonischen Anfrage als String. Die kanonische Anfrage definiert Elemente, die Nutzer in ihre Anfrage aufnehmen müssen, wenn sie Ihre signierte URL verwenden.

    Die kanonische Anfrage muss die folgende Struktur haben, einschließlich der Zeilenumbrüche zwischen den einzelnen Elementen:

    HTTP_VERB
    PATH_TO_RESOURCE
    CANONICAL_QUERY_STRING
    CANONICAL_HEADERS
    
    SIGNED_HEADERS
    UNSIGNED-PAYLOAD

    Die kanonische Anfrage besteht aus folgenden Komponenten:

    • HTTP_VERB: Das HTTP-Verb, das mit der signierten URL verwendet werden soll.

      Eine Liste der zulässigen Werte finden Sie unter HTTP-Verben.

    • PATH_TO_RESOURCE: Der Pfad zur Ressource, der nach dem Hostnamen beginnt. Wenn Sie den Pfad zur Ressource definieren, müssen Sie die folgenden reservierten Zeichen URL-konform codieren: ?=!#$&'()*+,:;@[]."

    • CANONICAL_QUERY_STRING: Die Abfragestringparameter, die Anfragen mit der signierten URL enthalten müssen. Fügen Sie Abfragestringparameter in alphabetischer Reihenfolge hinzu und trennen Sie die einzelnen Werte durch &.

    • CANONICAL_HEADERS: Die Name/Wert-Paare für die Anfrageheader, die Anfragen mit signierter URL enthalten müssen. Dazu zählen auch Erweiterungsheader. Fügen Sie Header in alphabetischer Reihenfolge hinzu und trennen Sie die einzelnen Werte durch \n.

    • SIGNED_HEADERS: Die Headernamen der CANONICAL_HEADERS, getrennt durch ;.

    • UNSIGNED-PAYLOAD: Dieser String muss in der letzten Zeile der kanonischen Anfrage angegeben sein.

  2. Verwenden einer SHA-256-Hash-Funktion, um einen Hex-codierten Hash-Wert der kanonischen Anfrage zu erstellen.

    Die Programmiersprache sollte eine Bibliothek zum Erstellen von SHA-256-Hash-Werten haben. Beispiel für einen Hash-Wert:

    436b7ce722d03b17d3f790255dd57904f7ed61c02ac5127a0ca8063877e4e42c
  3. Erstellen des zu signierenden Strings.

    Der zu signierende String muss einschließlich der Zeilenumbrüche zwischen den einzelnen Elementen die folgende Struktur haben:

    SIGNING_ALGORITHM
    CURRENT_DATETIME
    CREDENTIAL_SCOPE
    HASHED_CANONICAL_REQUEST

    Der zu signierende String besteht aus den folgenden Komponenten:

    • SIGNING_ALGORITHM: Muss GOOG4-RSA-SHA256 sein.

    • CURRENT_DATETIME: Das aktuelle Datum und die aktuelle Uhrzeit im ISO 8601-Basisformat YYYYMMDD'T'HHMMSS'Z'.

    • CREDENTIAL SCOPE: Der Anmeldedatenbereich der Anfrage zum Signieren des zu signierenden Strings.

    • HASHED_CANONICAL_REQUEST: Der Hex-codierte SHA-256-Hash-Wert der kanonischen Anfrage, den Sie im vorherigen Schritt erstellt haben.

  4. Signieren des zu signierenden Strings unter Verwendung einer RSA-Signatur mit SHA-256. Das Ergebnis dieser Signatur ist Ihre Anfragesignatur.

    Die Programmiersprache muss eine Bibliothek für RSA-Signaturen haben. Innerhalb einer Google App Engine-Anwendung können Sie den App Engine App Identity-Dienst zum Signieren des Strings verwenden.

  5. Erstellen der signierten URL mithilfe der folgenden Verkettung:

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

    Die signierte URL besteht aus folgenden Komponenten:

    • HOSTNAME: Muss https://storage.googleapis.com sein.

    • PATH_TO_RESOURCE: Muss mit dem Wert übereinstimmen, den Sie beim Erstellen der kanonischen Anfrage verwendet haben.

    • CANONICAL_QUERY_STRING: Muss mit den Werten übereinstimmen, die Sie beim Erstellen der kanonischen Anfrage verwendet haben.

    • REQUEST_SIGNATURE: Die aus der Verwendung einer RSA-Signatur im vorherigen Schritt resultierende Ausgabe.

    Die vollständige URL aus diesem Beispiel sieht so aus:

    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

Python-Beispielprogramm

Das folgende Beispiel zeigt eine Implementierung des Algorithmus zum Signieren von URLs. Das Beispiel verwendet die Programmiersprache 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
Hat Ihnen diese Seite weitergeholfen? Teilen Sie uns Ihr Feedback mit:

Feedback geben zu...