Xác Minh Chữ Ký Webhook: Cách Bảo Mật Tích Hợp

Ashley Innocent

Ashley Innocent

22 tháng 12 2025

Xác Minh Chữ Ký Webhook: Cách Bảo Mật Tích Hợp

Webhooks là một trong những cách mạnh mẽ nhất để nhận các cập nhật theo thời gian thực từ các dịch vụ bên thứ ba. Một yêu cầu HTTP POST duy nhất từ Stripe, GitHub, Shopify hoặc Twilio có thể kích hoạt các logic kinh doanh quan trọng trong ứng dụng của bạn — như tính phí khách hàng, cập nhật kho lưu trữ, vận chuyển đơn hàng hoặc gửi SMS xác nhận.

Nhưng mọi yêu cầu webhook đều được gửi qua internet công cộng. Và điều đó có nghĩa là bất kỳ ai đoán được hoặc phát hiện ra URL webhook của bạn đều có thể gửi các tải trọng độc hại trông hoàn toàn hợp lệ. Nếu không có xác thực đúng cách, ứng dụng của bạn không có cách nào để phân biệt giữa một sự kiện thật và một sự kiện giả mạo.

Đó là lúc xác minh chữ ký webhook phát huy tác dụng. Đây là một cơ chế đơn giản, được chuẩn hóa, đảm bảo rằng mọi yêu cầu webhook đến đều thực sự đến từ dịch vụ mà bạn mong đợi và không bị thay đổi trong quá trình truyền tải.

Trong hướng dẫn toàn diện này, bạn sẽ tìm hiểu chính xác cách hoạt động của xác minh chữ ký webhook, và cách triển khai nó một cách chính xác trong các ngôn ngữ lập trình phổ biến. Bạn cũng sẽ thấy những lỗi thường gặp cần tránh và cách kiểm tra mọi thứ từ đầu đến cuối — một cách nhanh chóng và đáng tin cậy.

💡
Trước khi đi sâu vào chi tiết kỹ thuật, tôi muốn đảm bảo rằng bạn có công cụ phù hợp để xác minh và gỡ lỗi webhooks chỉ trong vài phút. Apidog hoàn toàn miễn phí để tải xuống và cung cấp tính năng kiểm tra xác minh chữ ký webhook tích hợp sẵn, máy chủ giả lập và kiểm tra tải trọng theo thời gian thực — không yêu cầu thẻ tín dụng. Đây là cách nhanh nhất để xác nhận rằng logic xác minh của bạn thực sự hoạt động.
nút

Xác minh chữ ký Webhook là gì?

Xác minh chữ ký webhook là quá trình xác nhận rằng một yêu cầu webhook đến thực sự đến từ dịch vụ mà bạn mong đợi và không bị giả mạo.

Hầu hết các nhà cung cấp sử dụng HMAC (Mã xác thực thông điệp dựa trên hàm băm) với SHA-256 hoặc SHA-512. Dịch vụ tính toán:

signature = HMAC-SHA256(secret_key, payload)

Sau đó, họ gửi chữ ký trong một tiêu đề (thường là X-Signature, Signature, hoặc X-Hub-Signature-256).

Máy chủ của bạn:

  1. Nhận tải trọng dưới dạng byte thô (quan trọng!)
  2. Tính toán lại HMAC bằng cách sử dụng khóa bí mật đã lưu trữ của bạn
  3. So sánh chữ ký đã tính toán với chữ ký nhận được

Nếu chúng khớp chính xác, bạn xử lý webhook. Nếu không, bạn trả về HTTP 401 hoặc 403.

Tại sao HMAC-SHA256 là tiêu chuẩn công nghiệp

Các nhà cung cấp chọn HMAC-SHA256 vì những lý do sau:

GitHub, Stripe, Shopify, Slack và hàng chục dịch vụ khác đều sử dụng HMAC-SHA256.

Cách triển khai xác minh chữ ký Webhook trong Node.js

Hãy bắt đầu với một ví dụ thực tế trong Node.js.

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const computedSignature = hmac.update(payload).digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(computedSignature),
    Buffer.from(signature)
  );
}

Những điểm cần lưu ý:

Ví dụ về Express middleware:

app.post('/webhooks/stripe', (req, res, next) => {
  const signature = req.headers['stripe-signature'];
  const secret = process.env.STRIPE_WEBHOOK_SECRET;

  // Lấy body thô (Express cần middleware để giữ nguyên body thô)
  const rawBody = req.rawBody || req.body; // sử dụng body-parser với tùy chọn verify

  if (!verifyWebhookSignature(rawBody, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }

  // Chữ ký hợp lệ → xử lý sự kiện
  next();
});

Triển khai bằng Python (FastAPI + Pydantic)

from fastapi import FastAPI, Request, HTTPException
import hmac
import hashlib

app = FastAPI()

def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
    computed = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(computed, signature)

@app.post("/webhooks/github")
async def github_webhook(request: Request):
    signature = request.headers.get("X-Hub-Signature-256")
    if not signature:
        raise HTTPException(status_code=401, detail="Missing signature")

    payload = await request.body()

    if not verify_signature(payload, signature.split('=')[1], SECRET):
        raise HTTPException(status_code=401, detail="Invalid signature")

    # Xử lý webhook
    return {"status": "ok"}

Những cạm bẫy thường gặp mà nhà phát triển mắc phải (và cách tránh chúng)

1. Sử dụng JSON.stringify() hoặc Body đã phân tích

Nhiều framework tự động phân tích JSON. Điều này làm hỏng quá trình xác minh vì khoảng trắng, thứ tự khóa và định dạng có thể khác nhau.

Giải pháp: Luôn lấy nội dung body thô trước khi phân tích.

Trong Express: Sử dụng body-parser với { verify: true }

Trong FastAPI: Sử dụng await request.body()

2. So sánh chuỗi với ===

Các cuộc tấn công thời gian có thể làm lộ thông tin. Sử dụng crypto.timingSafeEqual hoặc hmac.compare_digest.

3. Lưu trữ khóa bí mật trong mã nguồn

Sử dụng biến môi trường hoặc trình quản lý bí mật (AWS Secrets Manager, HashiCorp Vault, v.v.).

4. Quên xử lý các cuộc tấn công phát lại

Hầu hết các nhà cung cấp đều bao gồm một dấu thời gian. Kiểm tra xem sự kiện có gần đây không (ví dụ: trong vòng 5 phút).

const timestamp = req.headers['X-Signature-Timestamp'];
if (Date.now() - timestamp > 5 * 60 * 1000) {
  return res.status(401).send('Dấu thời gian quá cũ');
}

5. Vẫn sử dụng SHA-1 (Vẫn còn xảy ra!)

GitHub đã ngừng sử dụng SHA-1 vào năm 2022. Luôn sử dụng SHA-256.

Kiểm tra xác minh chữ ký Webhook bằng Apidog

Kiểm tra webhook thủ công rất khó khăn. Bạn gửi yêu cầu, kiểm tra nhật ký, sửa lỗi, lặp lại.

Apidog giúp việc này trở nên dễ dàng:

Trong dự án Apidog của bạn, nhấp vào biểu tượng + ở thanh bên trái và chọn "New Other Protocol APIs" > "Webhook".

CleanShot 2025-11-05 at 17.18.02@2x.png

Sau khi tạo Webhook, hãy điền các trường sau vào trình chỉnh sửa:Phương thức yêu cầu: Thường làPOST.Tên Webhook: Tên này sẽ xuất hiện trong tài liệu API và xuất OpenAPI, ví dụ: order.URL gỡ lỗi (tùy chọn): URL thực tế được sử dụng để gửi các yêu cầu thử nghiệm. Lưu ý: Phần này chỉ dành cho mục đích thử nghiệm và sẽ không được đưa vào tài liệu.Thông tin khác: Chẳng hạn như nội dung yêu cầu (request body).

image.png

Nhấp vàoSavesau khi bạn đã điền đầy đủ các trường bắt buộc.
Chỉ cần nhập URL Webhook của bạn vào trường Debug URL, sau đó nhấp vào Send để mô phỏng một cuộc gọi Webhook.

image.png

Tôi đã tiết kiệm hàng giờ gỡ lỗi với trình giả lập webhook của Apidog. Nó thậm chí còn hỗ trợ định dạng stripe-signature chính xác của Stripe và tiền tố sha256=... của GitHub.

Ví dụ thực tế: Xác minh Webhooks của Stripe

Stripe sử dụng định dạng tiêu đề đặc biệt:

stripe-signature: t=1681234567,v1=abc123...,v0=def456...

Bạn phải:

Stripe cung cấp các thư viện chính thức để xử lý sự phức tạp này:

const stripe = require('stripe')('sk_...');
stripe.webhooks.constructEvent(payload, sigHeader, endpointSecret);

Nhưng việc hiểu rõ HMAC cơ bản là rất quan trọng khi bạn cần tự mình triển khai nó.

Các chủ đề nâng cao: Chấp nhận nhiều chữ ký

Một số nhà cung cấp (như Stripe) gửi nhiều chữ ký để tương thích ngược. Mã của bạn nên:

Các phương pháp bảo mật tốt nhất năm 2025

Kết luận: Bước xác minh nhỏ, lợi ích bảo mật lớn

Xác minh chữ ký webhook nghe có vẻ là một chi tiết nhỏ. Nhưng nó là sự khác biệt giữa một ứng dụng an toàn và một ứng dụng mà kẻ tấn công có thể dễ dàng khai thác.

Hãy triển khai nó một cách chính xác, kiểm tra kỹ lưỡng bằng các công cụ như Apidog, và bạn sẽ yên tâm hơn khi biết các tích hợp của mình được bảo vệ.

Tải Apidog miễn phí ngay hôm nay và xác minh webhook đầu tiên của bạn chỉ trong vòng 5 phút. Đây là cách nhanh nhất để chứng minh mã của bạn thực sự hoạt động.

nút

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API