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

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

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

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

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

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

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

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

* *Чтобы создать новый веб-перехватчик с секретным маркером*, см. раздел [Создание веб-перехватчиков](/ru/enterprise-server@3.22/webhooks/using-webhooks/creating-webhooks).
* *Чтобы добавить секретный маркер в существующий веб-перехватчик, измените параметры веб-перехватчика*. В разделе "Секрет" введите строку для использования в качестве `secret` ключа. Дополнительные сведения см. в разделе [Редактирование веб-перехватчиков](/ru/enterprise-server@3.22/webhooks/using-webhooks/editing-webhooks).

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

После создания секретного маркера необходимо сохранить его в безопасном расположении, к которому может получить доступ сервер. Никогда не закодировать маркер в приложение или отправить маркер в любой репозиторий. Дополнительные сведения об безопасном использовании учетных данных проверки подлинности в коде см. в разделе [Обеспечение безопасности учетных данных API](/ru/enterprise-server@3.22/rest/authentication/keeping-your-api-credentials-secure#use-authentication-credentials-securely-in-your-code).

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

GitHub будет использовать секретный токен для создания хэш-подписи, отправляемой вам с каждой полезной нагрузкой. Хэш-подпись будет отображаться в каждой доставке в качестве значения заголовка `X-Hub-Signature-256` . Дополнительные сведения см. в разделе [События и полезные данные веб-перехватчика](/ru/enterprise-server@3.22/webhooks/webhook-events-and-payloads#delivery-headers).

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

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

* GitHub использует хэш-дайджест HMAC для вычисления хэша.
* Хэш-подпись всегда начинается с `sha256=`.
* Хэш-подпись создается с помощью секретного маркера веб-перехватчика и содержимого полезных данных.
* Если в реализации языка и сервера указана кодировка символов, убедитесь, что полезные данные обрабатываются как символы UTF-8. Полезные данные веб-перехватчика могут содержать символы юникода.
* Никогда не используйте обычный `==` оператор. Вместо этого рекомендуется использовать такой метод [`secure_compare`](https://www.rubydoc.info/gems/rack/Rack%2FUtils:secure_compare) или [`crypto.timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b), который выполняет сравнение строк "постоянного времени" для устранения определенных атак времени на регулярные операторы равенства или регулярные циклы на языках, оптимизированных для JIT.

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

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

* `secret`: `It's a Secret to Everybody`
* `payload`: `Hello, World!`

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

* подпись: `757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17` <!-- markdownlint-disable-line GHD034 -->
* X-Hub-Signature-256: `sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17`

### Примеры

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

#### Пример Ruby

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

```ruby
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
```

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

```ruby
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` функцию и вызвать ее при получении полезных данных веб-перехватчика:

```python
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 при получении полезных данных веб-перехватчика:

```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 copy
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` не будет присутствовать, если вы не настроили секрет для веб-перехватчика. Дополнительные сведения о настройке секрета для веб-перехватчика см. в разделе [Редактирование веб-перехватчиков](/ru/enterprise-server@3.22/webhooks/using-webhooks/editing-webhooks).
* Убедитесь, что используется правильный заголовок. GitHub рекомендует использовать `X-Hub-Signature-256` заголовок, который использует алгоритм HMAC-SHA256. Заголовок `X-Hub-Signature` использует алгоритм HMAC-SHA1 и включается только в устаревшие цели.
* Убедитесь, что используется правильный алгоритм. При использовании заголовка `X-Hub-Signature-256` следует использовать алгоритм HMAC-SHA256.
* Убедитесь, что вы используете правильный секрет веб-перехватчика. Если вы не знаете значение секрета веб-перехватчика, вы можете обновить секрет веб-перехватчика. Дополнительные сведения см. в разделе [Редактирование веб-перехватчиков](/ru/enterprise-server@3.22/webhooks/using-webhooks/editing-webhooks).
* Убедитесь, что полезные данные и заголовки не изменяются перед проверкой. Например, если вы используете прокси-сервер или подсистему балансировки нагрузки, убедитесь, что прокси-сервер или подсистема балансировки нагрузки не изменяет полезные данные или заголовки.
* Если в реализации языка и сервера указана кодировка символов, убедитесь, что полезные данные обрабатываются как символы UTF-8. Полезные данные веб-перехватчика могут содержать символы юникода.

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

* [Обработка доставки веб-перехватчика](/ru/enterprise-server@3.22/webhooks/using-webhooks/handling-webhook-deliveries)
* [Рекомендации по использованию веб-перехватчиков](/ru/enterprise-server@3.22/webhooks/using-webhooks/best-practices-for-using-webhooks)