Чтобы подтвердить, что хука отправлен из МТС Линк в заголовок HTTP запроса встроен код для проверки.
При создании нового вебхука можно задать поле "секретная фраза". Если для вебхука был задан секрет, то POST-запрос вебхука будет содержать подпись в заголовке X-Webhook-Signature. Подпись представляет собой код аутентификации (проверки подлинности) сообщения на основе хэша (HMAC) c алгоритмом SHA-256.
Для определения подлинности вебхука необходимо выполнить следующие действия:
PHP
<?php
function verifySignature($payload, $headerSignature, $secretKey) {
$expectedSignature = hash_hmac('sha256', $payload, $secretKey);
return hash_equals($expectedSignature, $headerSignature);
}
$headers = getallheaders();
$headerSignature = $headers['X-Webhook-Signature'] ?? '';
$payload = file_get_contents("php://input");
$secretKey = 'SuperSecret';
if (verifySignature($payload, $headerSignature, $secretKey)) {
echo "Webhook signature is valid";
} else {
echo "Invalid webhook signature";
}Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"io/ioutil"
"net/http"
)
func verifySignature(payload []byte, headerSignature string, secretKey string) bool {
h := hmac.New(sha256.New, []byte(secretKey))
h.Write(payload)
expectedSignature := hex.EncodeToString(h.Sum(nil))
return hmac.Equal([]byte(expectedSignature), []byte(headerSignature))
}
func handler(w http.ResponseWriter, r *http.Request) {
payload, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Unable to read request body", http.StatusBadRequest)
return
}
headerSignature := r.Header.Get("X-Webhook-Signature")
secretKey := "SuperSecret"
if verifySignature(payload, headerSignature, secretKey) {
fmt.Fprintln(w, "Webhook signature is valid")
} else {
http.Error(w, "Invalid webhook signature", http.StatusUnauthorized)
}
}
func main() {
http.HandleFunc("/webhook", handler)
http.ListenAndServe(":8080", nil)
}Ruby
def verify_signature(payload_body)
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], payload_body)
return halt 500, "Invalid webhook signature" unless Rack::Utils.secure_compare(signature, request.env['X-Webhook-Signature'])
end
post '/webhook' do
request.body.rewind
payload_body = request.body.read
verify_signature(payload_body)
push = JSON.parse(payload_body)
"I got some JSON: #{push.inspect}"
endJavaScript
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
import { Webhooks } from "@octokit/webhooks";
const webhooks = new Webhooks({
secret: process.env.WEBHOOK_SECRET,
});
const handleWebhook = async (req, res) => {
const signature = req.headers["X-Webhook-Signature"];
const body = await req.text();
if (!(await webhooks.verify(body, signature))) {
res.status(403).send("Forbidden");
return;
}
// Остальная логика здесь
};Python
import hashlib
import hmac
def verify_signature(payload_body, secret_token, signature_header):
"""Убедитесь, что вебхук был отправлен с МТС.Линк, выполнив проверку SHA256.
В случае неудачной проверки возвращается ошибка 403.
Аргументы:
payload_body: исходное тело запроса для проверки (request.body())
secret_token: секрет вебхука (SECRET_TOKEN)
signature_header: заголовок с подписью (X-Webhook-Signature)
"""
if not signature_header:
raise HTTPException(status_code=403, detail="X-Webhook-Signature header is missing!")
hash_object = hmac.new(secret_token.encode('utf-8'), msg=payload_body, digestmod=hashlib.sha256)
expected_signature = hash_object.hexdigest()
if not hmac.compare_digest(expected_signature, signature_header):
raise HTTPException(status_code=403, detail="Invalid webhook signature")