Skip to main content

Проверка доставки веб-перехватчика

Секрет веб-перехватчика можно использовать для проверки того, что доставка веб-перехватчика осуществляется из GitHub.

Проверка доставки веб-перехватчика

После настройки сервера для получения полезных данных он будет прослушивать любую доставку, отправленную в настроенную конечную точку. Чтобы убедиться, что сервер обрабатывает только поставки веб-перехватчика, отправленные GitHub и чтобы убедиться, что доставка не была изменена, перед дальнейшей обработкой доставки необходимо проверить подпись веб-перехватчика. Это поможет избежать затрат на время сервера для обработки поставок, которые не относятся к GitHub и помогут избежать атак в середине.

Для этого необходимо выполнить следующие действия.

  1. Создайте секретный маркер для веб-перехватчика.
  2. Безопасно храните маркер на сервере.
  3. Проверьте входящие полезные данные веб-перехватчика по маркеру, чтобы убедиться, что они исходят из GitHub и не были изменены.

Создание секретного токена

Вы можете создать новый веб-перехватчик с секретным маркером или добавить маркер секрета в существующий веб-перехватчик. При создании секретного токена следует выбрать случайную строку текста с высокой энтропией.

  • Сведения о создании веб-перехватчика с секретным маркером см. в разделе "Создание веб-перехватчиков".
  • Чтобы добавить секретный маркер в существующий веб-перехватчик, измените параметры веб-перехватчика. В разделе "Секрет" введите строку для использования в качестве secret ключа. Дополнительные сведения см. в разделе Редактирование веб-перехватчиков.

Безопасное хранение маркера секрета

После создания секретного маркера необходимо сохранить его в безопасном расположении, к которому может получить доступ сервер. Никогда не закодировать маркер в приложение или отправить маркер в любой репозиторий. Дополнительные сведения об безопасном использовании учетных данных проверки подлинности в коде см. в разделе "Обеспечение безопасности учетных данных API".

Проверка доставки веб-перехватчика

GitHub Enterprise Cloud будет использовать секретный токен для создания хэш-подписи, отправляемой вам с каждой полезной нагрузкой. Хэш-подпись будет отображаться в каждой доставке в качестве значения заголовка X-Hub-Signature-256 . Дополнительные сведения см. в разделе События и полезные данные веб-перехватчика.

В коде, который обрабатывает поставки веб-перехватчика, следует вычислить хэш с помощью секретного токена. Затем сравните хэш, который GitHub отправлен с ожидаемым хэшом, который вы вычислили, и убедитесь, что они соответствуют. Примеры проверки хэшей на различных языках программирования см. в разделе "Примеры".

При проверке полезных данных веб-перехватчика следует учитывать несколько важных моментов:

  • GitHub Enterprise Cloud использует хэш-хэш HMAC.
  • Хэш-подпись всегда начинается с sha256=.
  • Хэш-подпись создается с помощью секретного маркера веб-перехватчика и содержимого полезных данных.
  • Если в реализации языка и сервера указана кодировка символов, убедитесь, что полезные данные обрабатываются как символы UTF-8. Полезные данные веб-перехватчика могут содержать символы юникода.
  • Никогда не используйте обычный == оператор. Вместо этого рекомендуется использовать такой метод secure_compare или crypto.timingSafeEqual, который выполняет сравнение строк "постоянного времени" для устранения определенных атак времени на регулярные операторы равенства или регулярные циклы на языках, оптимизированных для JIT.

Тестирование проверки полезных данных веб-перехватчика

Для проверки правильности реализации можно использовать следующие secret и payload значения:

  • secret: "Это секрет для всех"
  • payload: "Привет, мир!"

Если реализация правильна, создаваемые подписи должны соответствовать следующим значениям подписи:

  • Подпись: 757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17
  • X-Hub-Signature-256: sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17

Примеры

Вы можете использовать язык программирования для реализации проверки HMAC в коде. Ниже приведены некоторые примеры того, как реализация может выглядеть на различных языках программирования.

Пример Ruby

Например, можно определить следующую verify_signature функцию:

def verify_signature(payload_body)
  signature = 'sha256=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload_body)
  return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, request.env['HTTP_X_HUB_SIGNATURE_256'])
end

Затем его можно вызвать при получении полезных данных веб-перехватчика:

post '/payload' do
  request.body.rewind
  payload_body = request.body.read
  verify_signature(payload_body)
  push = JSON.parse(payload_body)
  "I got some JSON: #{push.inspect}"
end

Пример на Python

Например, можно определить следующую verify_signature функцию и вызвать ее при получении полезных данных веб-перехватчика:

import hashlib
import hmac
def verify_signature(payload_body, secret_token, signature_header):
    """Verify that the payload was sent from GitHub by validating SHA256.

    Raise and return 403 if not authorized.

    Args:
        payload_body: original request body to verify (request.body())
        secret_token: GitHub app webhook token (WEBHOOK_SECRET)
        signature_header: header received from GitHub (x-hub-signature-256)
    """
    if not signature_header:
        raise HTTPException(status_code=403, detail="x-hub-signature-256 header is missing!")
    hash_object = hmac.new(secret_token.encode('utf-8'), msg=payload_body, digestmod=hashlib.sha256)
    expected_signature = "sha256=" + hash_object.hexdigest()
    if not hmac.compare_digest(expected_signature, signature_header):
        raise HTTPException(status_code=403, detail="Request signatures didn't match!")

Пример JavaScript

Например, можно определить следующую verifySignature функцию и вызвать ее в любой среде JavaScript при получении полезных данных веб-перехватчика:

let encoder = new TextEncoder();

async function verifySignature(secret, header, payload) {
    let parts = header.split("=");
    let sigHex = parts[1];

    let algorithm = { name: "HMAC", hash: { name: 'SHA-256' } };

    let keyBytes = encoder.encode(secret);
    let extractable = false;
    let key = await crypto.subtle.importKey(
        "raw",
        keyBytes,
        algorithm,
        extractable,
        [ "sign", "verify" ],
    );

    let sigBytes = hexToBytes(sigHex);
    let dataBytes = encoder.encode(payload);
    let equal = await crypto.subtle.verify(
        algorithm.name,
        key,
        sigBytes,
        dataBytes,
    );

    return equal;
}

function hexToBytes(hex) {
    let len = hex.length / 2;
    let bytes = new Uint8Array(len);

    let index = 0;
    for (let i = 0; i < hex.length; i += 2) {
        let c = hex.slice(i, i + 2);
        let b = parseInt(c, 16);
        bytes[index] = b;
        index += 1;
    }

    return bytes;
}

Пример TypeScript

Например, можно определить следующую verify_signature функцию и вызвать ее при получении полезных данных веб-перехватчика:

JavaScript
import * as crypto from "crypto";

const WEBHOOK_SECRET: string = process.env.WEBHOOK_SECRET;

const verify_signature = (req: Request) => {
  const signature = crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest("hex");
  let trusted = Buffer.from(`sha256=${signature}`, 'ascii');
  let untrusted =  Buffer.from(req.headers.get("x-hub-signature-256"), 'ascii');
  return crypto.timingSafeEqual(trusted, untrusted);
};

const handleWebhook = (req: Request, res: Response) => {
  if (!verify_signature(req)) {
    res.status(401).send("Unauthorized");
    return;
  }
  // The rest of your logic here
};

Устранение неполадок

Если вы уверены, что полезные данные находятся из GitHub, но проверка подписи завершается ошибкой:

  • Убедитесь, что вы настроили секрет для веб-перехватчика. Заголовок X-Hub-Signature-256 не будет присутствовать, если вы не настроили секрет для веб-перехватчика. Дополнительные сведения о настройке секрета для веб-перехватчика см. в разделе "Редактирование веб-перехватчиков".
  • Убедитесь, что используется правильный заголовок. GitHub рекомендует использовать X-Hub-Signature-256 заголовок, который использует алгоритм HMAC-SHA256. Заголовок X-Hub-Signature использует алгоритм HMAC-SHA1 и включается только в устаревшие цели.
  • Убедитесь, что используется правильный алгоритм. При использовании заголовка X-Hub-Signature-256 следует использовать алгоритм HMAC-SHA256.
  • Убедитесь, что вы используете правильный секрет веб-перехватчика. Если вы не знаете значение секрета веб-перехватчика, вы можете обновить секрет веб-перехватчика. Дополнительные сведения см. в разделе Редактирование веб-перехватчиков.
  • Убедитесь, что полезные данные и заголовки не изменяются перед проверкой. Например, если вы используете прокси-сервер или подсистему балансировки нагрузки, убедитесь, что прокси-сервер или подсистема балансировки нагрузки не изменяет полезные данные или заголовки.
  • Если в реализации языка и сервера указана кодировка символов, убедитесь, что полезные данные обрабатываются как символы UTF-8. Полезные данные веб-перехватчика могут содержать символы юникода.

Дополнительные материалы