Проверка доставки веб-перехватчика
После настройки сервера для получения полезных данных он будет прослушивать любую доставку, отправленную в настроенную конечную точку. Чтобы убедиться, что сервер обрабатывает только поставки веб-перехватчика, отправленные GitHub и чтобы убедиться, что доставка не была изменена, перед дальнейшей обработкой доставки необходимо проверить подпись веб-перехватчика. Это поможет избежать затрат на время сервера для обработки поставок, которые не относятся к GitHub и помогут избежать атак в середине.
Для этого необходимо выполнить следующие действия.
- Создайте секретный маркер для веб-перехватчика.
- Безопасно храните маркер на сервере.
- Проверьте входящие полезные данные веб-перехватчика по маркеру, чтобы убедиться, что они исходят из GitHub и не были изменены.
Создание секретного токена
Вы можете создать новый веб-перехватчик с секретным маркером или добавить маркер секрета в существующий веб-перехватчик. При создании секретного токена следует выбрать случайную строку текста с высокой энтропией.
- Сведения о создании веб-перехватчика с секретным маркером см. в разделе "Создание веб-перехватчиков".
- Чтобы добавить секретный маркер в существующий веб-перехватчик, измените параметры веб-перехватчика. В разделе "Секрет" введите строку для использования в качестве
secret
ключа. Дополнительные сведения см. в разделе Редактирование веб-перехватчиков.
Безопасное хранение маркера секрета
После создания секретного маркера необходимо сохранить его в безопасном расположении, к которому может получить доступ сервер. Никогда не закодировать маркер в приложение или отправить маркер в любой репозиторий. Дополнительные сведения об безопасном использовании учетных данных проверки подлинности в коде см. в разделе "Обеспечение безопасности учетных данных API".
Проверка доставки веб-перехватчика
GitHub будет использовать секретный токен для создания хэш-подписи, отправляемой вам с каждой полезной нагрузкой. Хэш-подпись будет отображаться в каждой доставке в качестве значения заголовка X-Hub-Signature-256
. Дополнительные сведения см. в разделе События и полезные данные веб-перехватчика.
В коде, который обрабатывает поставки веб-перехватчика, следует вычислить хэш с помощью секретного токена. Затем сравните хэш, который GitHub отправлен с ожидаемым хэшом, который вы вычислили, и убедитесь, что они соответствуют. Примеры проверки хэшей на различных языках программирования см. в разделе "Примеры".
При проверке полезных данных веб-перехватчика следует учитывать несколько важных моментов:
- GitHub использует хэш-хэш 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
функцию и вызвать ее при получении полезных данных веб-перехватчика:
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. Полезные данные веб-перехватчика могут содержать символы юникода.