Проверка доставки веб-перехватчика
После настройки сервера для получения полезных данных он будет прослушивать любую доставку, отправленную в настроенную конечную точку. Чтобы убедиться, что сервер обрабатывает только поставки веб-перехватчика, отправленные GitHub и чтобы убедиться, что доставка не была изменена, перед дальнейшей обработкой доставки необходимо проверить подпись веб-перехватчика. Это поможет избежать затрат на время сервера для обработки поставок, которые не относятся к GitHub и помогут избежать атак в середине.
Для этого необходимо выполнить следующие действия.
- Создайте секретный маркер для веб-перехватчика.
 - Безопасно храните маркер на сервере.
 - Проверьте входящие полезные данные веб-перехватчика по маркеру, чтобы убедиться, что они приходят из GitHub и не были изменены.
 
Создание секретного токена
Вы можете создать новый веб-перехватчик с секретным маркером или добавить маркер секрета в существующий веб-перехватчик. При создании секретного токена следует выбрать случайную строку текста с высокой энтропией.
- Чтобы создать новый веб-перехватчик с секретным маркером, см. раздел Создание веб-перехватчиков.
 - Чтобы добавить секретный маркер в существующий веб-перехватчик, измените параметры веб-перехватчика. В разделе "Секрет" введите строку для использования в качестве 
secretключа. Дополнительные сведения см. в разделе Редактирование веб-перехватчиков. 
Безопасное хранение маркера секрета
После создания секретного маркера необходимо сохранить его в безопасном расположении, к которому может получить доступ сервер. Никогда не закодировать маркер в приложение или отправить маркер в любой репозиторий. Дополнительные сведения об безопасном использовании учетных данных проверки подлинности в коде см. в разделе Обеспечение безопасности учетных данных API.
Проверка доставки веб-перехватчика
GitHub будет использовать секретный маркер для создания хэш-подписи, отправленной вам с каждой полезной нагрузкой. Хэш-подпись будет отображаться в каждой доставке в качестве значения заголовка X-Hub-Signature-256 . Дополнительные сведения см. в разделе События и полезные данные веб-перехватчика.
В коде, который обрабатывает поставки веб-перехватчика, следует вычислить хэш с помощью секретного токена. Затем сравните хэш, который GitHub отправлен с ожидаемым хэшом, который вы вычислили, и убедитесь, что они соответствуют. Примеры проверки хэшей на различных языках программирования см . в примерах.
При проверке полезных данных веб-перехватчика следует учитывать несколько важных моментов:
- GitHub использует хэш-дайджест HMAC.
 - Хэш-подпись всегда начинается с 
sha256=. - Хэш-подпись создается с помощью секретного маркера веб-перехватчика и содержимого полезных данных.
 - Если в реализации языка и сервера указана кодировка символов, убедитесь, что полезные данные обрабатываются как символы UTF-8. Полезные данные веб-перехватчика могут содержать символы юникода.
 - Никогда не используйте обычный 
==оператор. Вместо этого рекомендуется использовать такой методsecure_compareилиcrypto.timingSafeEqual, который выполняет сравнение строк "постоянного времени" для устранения определенных атак времени на регулярные операторы равенства или регулярные циклы на языках, оптимизированных для JIT. 
Тестирование проверки полезных данных веб-перехватчика
Для проверки правильности реализации можно использовать следующие secret и payload значения:
secret:It's a Secret to Everybodypayload:Hello, World!
Если реализация правильна, создаваемые подписи должны соответствовать следующим значениям подписи:
- подпись: 
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 функцию и вызвать ее при получении полезных данных веб-перехватчика:
import { Webhooks } from "@octokit/webhooks";
const webhooks = new Webhooks({
  secret: process.env.WEBHOOK_SECRET,
});
const handleWebhook = async (req, res) => {
  const signature = req.headers["x-hub-signature-256"];
  const body = await req.text();
  if (!(await webhooks.verify(body, signature))) {
    res.status(401).send("Unauthorized");
    return;
  }
  // The rest of your logic here
};
import { Webhooks } from "@octokit/webhooks";
const webhooks = new Webhooks({
  secret: process.env.WEBHOOK_SECRET,
});
const handleWebhook = async (req, res) => {
  const signature = req.headers["x-hub-signature-256"];
  const body = await req.text();
  if (!(await webhooks.verify(body, signature))) {
    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. Полезные данные веб-перехватчика могут содержать символы юникода.