บทความเกี่ยวกับ: BentoWeb API

การตรวจสอบ Signature ของ BentoWeb Webhook ด้วย HMAC-SHA256

🔐 การตรวจสอบ Signature ของ BentoWeb Webhook ด้วย HMAC-SHA256



เมื่อคุณรับ Webhook จาก BentoWeb ระบบจะส่งข้อมูลมาพร้อมกับ Signature เพื่อให้คุณสามารถตรวจสอบความถูกต้องของข้อมูล และป้องกันการปลอมแปลงได้


📬 ข้อมูลที่คุณจะได้รับจาก Webhook



Body: JSON Payload
Header:
Authorization: Signature สำหรับตรวจสอบ


🔑 หลักการสร้าง Signature



Signature ถูกสร้างจาก:

HMAC_SHA256(client_id + json_payload, client_secret)


โดย
client_id คือรหัสประจำระบบของคุณ
json_payload คือข้อมูลใน body (ต้อง normalize ก่อน hash)
client_secret คือรหัสลับที่คุณได้รับจาก BentoWeb


⚠️ จุดสำคัญที่ทำให้ Signature ไม่ตรง



JSON ที่รับมามีการ escape unicode (\u0e1e) ซึ่งต้องแปลงกลับก่อน
ช่องว่างหรือลำดับ key เปลี่ยนไปตอนทำ json_encode() ใหม่
ไม่ได้ใช้ UTF-8 encoding ก่อน hash
ใช้ hash ผิดประเภท (ต้องใช้ HMAC-SHA256 เท่านั้น)
Authorization ไม่มีการส่งค่า โปรดติดต่อเจ้าหน้าที่ เพื่อระบุ ID ร้านลงในตัว Client ID ที่คุณใช้งานอยู่


✅ ขั้นตอนการตรวจสอบ Signature


รับ Authorization จาก header
รับ raw body JSON
json_decode() เป็น object/array
json_encode() กลับแบบไม่ escape:
ต้องใช้ JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES (หรือเทียบเท่า)
รวม client_id + json
สร้าง HMAC-SHA256 ด้วย client_secret
เปรียบเทียบกับ Signature ที่ส่งมา


🔧 ตัวอย่างโค้ดในหลายภาษา



🐘 PHP



$raw = file_get_contents('php://input');
$data = json_decode($raw, true);

$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$baseString = 'your_client_id' . $json;

$expected = hash_hmac('sha256', $baseString, 'your_client_secret');
$provided = $_SERVER['HTTP_AUTHORIZATION'];

if (!hash_equals($expected, $provided)) {
    http_response_code(403);
    exit('Signature mismatch');
}


🐍 Python



import json, hmac, hashlib
from flask import request

client_id = "your_client_id"
client_secret = b"your_client_secret"

raw = request.get_data(as_text=True)
data = json.loads(raw)
json_string = json.dumps(data, ensure_ascii=False, separators=(',', ':'))

base_string = client_id + json_string
expected_signature = hmac.new(client_secret, base_string.encode('utf-8'), hashlib.sha256).hexdigest()

if request.headers.get('Authorization') != expected_signature:
    return "Signature mismatch", 403



🌐 Node.js



const crypto = require('crypto');
const express = require('express');
const app = express();

app.use(express.json({ verify: (req, res, buf) => req.rawBody = buf }));

app.post('/webhook', (req, res) => {
  const clientId = "your_client_id";
  const clientSecret = "your_client_secret";
  const json = JSON.stringify(req.body);
  const baseString = clientId + json;

  const expectedSignature = crypto.createHmac('sha256', clientSecret)
    .update(baseString, 'utf8')
    .digest('hex');

  const providedSignature = req.get('Authorization');

  if (providedSignature !== expectedSignature) {
    return res.status(403).send('Signature mismatch');
  }

  res.send('OK');
});


🦫 Go



import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "io/ioutil"
    "net/http"
)

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    clientId := "your_client_id"
    clientSecret := "your_client_secret"

    body, _ := ioutil.ReadAll(r.Body)
    var payload map[string]interface{}
    json.Unmarshal(body, &payload)

    jsonBytes, _ := json.Marshal(payload)
    baseString := clientId + string(jsonBytes)

    mac := hmac.New(sha256.New, []byte(clientSecret))
    mac.Write([]byte(baseString))
    expectedSignature := hex.EncodeToString(mac.Sum(nil))

    providedSignature := r.Header.Get("Authorization")

    if providedSignature != expectedSignature {
        http.Error(w, "Signature mismatch", http.StatusForbidden)
        return
    }

    w.Write([]byte("OK"))
}



🧪 ทดสอบลายเซ็นไม่ตรง


หากคุณทดสอบแล้วลายเซ็นไม่ตรง ให้ตรวจสอบว่า:
JSON ถูก encode ซ้ำหรือ escape ไม่ตรง (ไม่ escape unicode, ไม่มีช่องว่าง)
ตรวจว่าใช้ HMAC-SHA256
ตรวจว่าใช้ UTF-8 encoding
client_id หรือ client_secret ไม่ถูกต้อง
มีการแก้ไข body หลังจาก verify แล้ว
มี request จากภายนอกที่ไม่ใช่ BentoWeb

อัปเดตเมื่อ: 26/05/2025

บทความนี้เป็นประโยชน์หรือไม่?

แบ่งปันความคิดเห็นของคุณ

ยกเลิก

ขอบคุณ!