Google Cloud CDN подписан с использованием URLPrefix - PullRequest
0 голосов
/ 19 апреля 2020

Я не могу получить подписанный URL-адрес, работающий с URL-префиксом для CDN Google Cload.

Я настроил корзину, которая является серверной корзиной для моего экземпляра Cloud CDN. Я успешно настроил ключ подписи URL и создал рабочий подписанный URL для указанного c пути. Все используют инструкцию, найденную в https://cloud.google.com/cdn/docs/using-signed-urls?hl=en_US

Используя мою функцию signCdnUrl2, приведенную ниже. может создать рабочий подписанный URL для указанного ресурса c, например,

https://example.com/foo.mp4?Expires= [EXPIRATION] & KeyName = [KEY_NAME] & Signature = [SIGNATURE]

export function signCdnUrl2(fileName: string, opts: SignedUrlOptions, urlPrefix?: string) {
    const expireVal = '' + new Date().getTime() + opts.expires;
    const urlToSign = `${opts.baseUrl}/${fileName}?Expires=${expireVal}&KeyName=${opts.keyName}`;

    // Compute signature
    const keyBuffer = Buffer.from(opts.keyBase64, 'base64');
    let signature = createHmac('sha1', keyBuffer).update(urlToSign).digest('base64');
    signature = Base64urlUtil.escape(signature);

    // Add signature to urlToSign and return signedUrl
    return urlToSign + `&Signature=${signature}`;
}

Я хочу избежать «необходимости создавать новую подпись для каждого отдельного URL», поэтому я следую инструкциям на https://cloud.google.com/cdn/docs/using-signed-urls?hl=en_US#url -prefix , чтобы добавить параметр префикса URL.

Я не могу успешно создать рабочий подписанный URL с префиксом. Моя текущая попытка ниже

export function signCdnUrl3(fileName: string, opts: SignedUrlOptions, urlPrefix?: string) {

    const expireVal = '' + new Date().getTime() + opts.expires;

    const urlPrefixCombined = `${opts.baseUrl}${urlPrefix}`;
    // UrlPrefix param if provided otherwise empty string
    const urlPrefixEncoded = urlPrefix ? Base64urlUtil.encode(urlPrefixCombined) : '';

    // Param string to be signed with key
    const paramsToSign = `URLPrefix=${urlPrefixEncoded}&Expires=${expireVal}&KeyName=${opts.keyName}`;

    // Compute signature
    const keyBuffer = Buffer.from(opts.keyBase64, 'base64');
    let signature = createHmac('sha1', keyBuffer).update(paramsToSign).digest('base64');
    signature = Base64urlUtil.escape(signature);

    // Add signature to url
    return `${opts.baseUrl}/${fileName}?${paramsToSign}&Signature=${signature}`;
}

Я получаю ответ 403 из облачного CDN, если я пытаюсь получить доступ к любому ресурсу с данным префиксом в случае root корзины

403 Response

Запись в журнале от балансировщика нагрузки показывает, что он обнаруживает недействительную подпись

Load Balancer Log

Is что-то неправильно интерпретируется в инструкциях или я что-то пропустил в своей реализации? Будем благодарны за любые рекомендации.

Добавлен код Base64Util для полноты

export class Base64urlUtil {

    public static encode(str: string, encoding: any = 'utf8'): string {
        const buffer: Buffer = Buffer.from(str, encoding);
        const encodedStr: string = buffer.toString('base64');
        const final: string = Base64urlUtil.escape(encodedStr);
        return final;
    }

    public static decode(str: string, encoding?: string): string {
        return Buffer.from(Base64urlUtil.unescape(str), 'base64').toString(encoding || 'utf8');
    }

    public static escape(str: string): string {
        return str.replace(/\+/g, '-')
            .replace(/\//g, '_')
            .replace(/=/g, '');
    }

    public static unescape(str: string): string {
        return (str + '==='.slice((str.length + 3) % 4))
            .replace(/-/g, '+')
            .replace(/_/g, '/');
    }
}

Обновление

Использование реализации, предоставленной @elithrar { ссылка } Я поменял его выборочные значения в SignParams на собственные значения.

let signedParams = signURLPrefix(
  "https://<my-server>/sample/360p/",
  1588291200,
  "<my-key>",
  "<valid-key>"
)

Результат был такой:

URLPrefix = aHR0cHM6Ly9zcHluYWwucmNmc29mdHdhcmUuaW8vc2FtcGxlLzM2MHAv & Expires = 1588291200 & KeyName = my-key-name & Signature = wrbOloT + m31ZnQZe * 10 * 64 * 64 * 64 https://my-server/sample/360p/video.mp4?URLPrefix=aHR0cHM6Ly9zcHluYWwucmNmc29mdHdhcmUuaW8vc2FtcGxlLzM2MHAv&Expires=1588291200&KeyName=my-key-name&Signature=wrbOloT+m31ZnQZei2Csqq0XaGY=

Я получаю тот же ответ 403 и соответствующую недействительную подпись в журналах cdn

CDN log

Попытка использовать два разных ключа подписи, которые отлично работали для подписи одного указанного c URL без префикса url.

Ответы [ 2 ]

1 голос
/ 23 апреля 2020

У меня такая же проблема по этому поводу. Подписанный URL с URLPrefix и подписанный повар ie оба не работают. Я пытался реализовать с помощью Golang / Ruby, и я уверен, что подписанный лог c такой же, как в примере Golang.

После того, как он спросил службу поддержки Google, они сказали: «Поскольку эта функция была Недавно они переехали в GA, и выяснилось, что в вашем проекте он не был правильно включен. Для решения этой проблемы внедрено исправление, и я ожидаю, что оно будет полностью развернуто к следующей неделе. Я обновлю вас, как только исправление будет применено. «. Я думаю, что он также был неправильно включен в вашем проекте.

Я попытаюсь снова и обновлю информацию, как только исправление будет применено на следующей неделе.

Обновление

Мы получаем последний ответ службы поддержки Google о том, что наш проект включил эту функцию. Мой код работает без каких-либо изменений.

0 голосов
/ 20 апреля 2020

Не совсем понятно, что не так - я подозреваю, что вы можете использовать двойное base64-кодирование подписи, но Base64urlUtil не входит в предоставленный вами фрагмент.

Вот рабочая версия, которая генерирует ту же сигнатуру, что и тесты для Go образца кода :

const crypto = require("crypto")

export function signURLPrefix(
  urlPrefix: string,
  expires: number,
  keyName: string,
  key: string
) {
  const expireVal = expires
  const urlPrefixEncoded = Buffer.from(urlPrefix)
     .toString("base64")
     .replace(/_/g, '/')
     .replace(/-/g, '+')

  // Param string to be signed with key
  const paramsToSign = `URLPrefix=${urlPrefixEncoded}&Expires=${expireVal}&KeyName=${keyName}`

  // Compute signature
  const keyBytes = Buffer.from(key, "base64")
  // Expected key: []byte{0x9d, 0x9b, 0x51, 0xa2, 0x17, 0x4d, 0x17, 0xd9,
  // 0xb7, 0x70, 0xa3, 0x36, 0xe0, 0x87, 0x0a, 0xe3}
  let signature = crypto
    .createHmac("sha1", keyBytes)
    .update(paramsToSign)
    .digest("base64")
    .replace(/_/g, '/')
    .replace(/-/g, '+')

  return `${paramsToSign}&Signature=${signature}`
}

let signedParams = signURLPrefix(
  "https://media.example.com/segments/",
  1558131350,
  "my-key",
  "nZtRohdNF9m3cKM24IcK4w=="
)

let expected =
  "URLPrefix=aHR0cHM6Ly9tZWRpYS5leGFtcGxlLmNvbS9zZWdtZW50cy8=&Expires=1558131350&KeyName=my-key&Signature=HWE5tBTZgnYVoZzVLG7BtRnOsgk="

if (signedParams === expected) {
  console.log("✔️ Signature matches")
} else {
  console.error(
    `❌ Does not match: \n\tgot ${signedParams},\n\twant ${expected}`
  )
}

Вывод:

➜  ts-node signed_prefix.ts
✔️ Signature matches
...