How to verify Webhook signature from Monoova with PHP

Aug. 15, 2024 · boychawin

วันนี้มาปล่อยของครับ มาดูวิธีการยืนยันลายเซ็น Webhook จาก Monoova ก็คือ การยืนยันลายเซ็นของข้อมูลที่ส่งมานั้น เป็นขั้นตอนสำคัญเพื่อป้องกันการปลอมแปลงข้อมูล บทความนี้จะอธิบายขั้นตอนในการยืนยันลายเซ็น Webhook ด้วยภาษา PHP อ่าน API Documentation

1. การดึง Headers จากคำขอ


function get_ds_headers() {
    $headers = array();
    foreach ($_SERVER as $key => $value) {
        if (strpos($key, 'HTTP_') === 0) {
            $headers[str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))))] = $value;
        }
    }
    return $headers;
}

ฟังก์ชัน get_ds_headers() ใช้ในการดึง headers จากคำขอ HTTP ซึ่งประกอบด้วยข้อมูลสำคัญ เช่น ลายเซ็นการยืนยัน (Verification Signature) ที่เราต้องใช้ในการตรวจสอบความถูกต้อง

2. การดึง Payload ของ Webhook


$payload = file_get_contents('php://input');

ขั้นตอนนี้คือการดึงข้อมูล Payload ซึ่งเป็นข้อมูลหลักที่ Webhook ส่งมา คุณจะต้องใช้ข้อมูลนี้ในการยืนยันลายเซ็น

3. การยืนยันลายเซ็นโดยใช้ใบรับรอง (Certificate)


function certificate($path, $verificationSignature, $payload) {
    $certificate = file_get_contents("$path/public/v1/certificate");
    $signature = base64_decode($verificationSignature);
    $certificate_pem = chunk_split(base64_encode($certificate), 64, "\n");
    $certificate_pem = "-----BEGIN CERTIFICATE-----\n" . $certificate_pem . "-----END CERTIFICATE-----\n";
    $public_key_resource = openssl_get_publickey($certificate_pem);
    $verifyResult = openssl_verify($payload, $signature, $public_key_resource, OPENSSL_ALGO_SHA256);
    return $verifyResult;
}

ฟังก์ชัน certificate() ทำหน้าที่ตรวจสอบลายเซ็นที่ได้รับจาก Webhook โดยจะใช้ใบรับรอง (Certificate) จากเซิร์ฟเวอร์ของ Monoova มายืนยันข้อมูล

  • โหลดใบรับรอง: ใช้ file_get_contents() เพื่อดึงใบรับรองจาก URL ที่กำหนดไว้
  • ถอดรหัสลายเซ็น: ใช้ base64_decode() เพื่อถอดรหัสลายเซ็นที่ได้รับมา
  • ยืนยันลายเซ็น: ใช้ openssl_verify() เพื่อเปรียบเทียบลายเซ็นที่ได้รับกับลายเซ็นที่สร้างขึ้นจากข้อมูล Payload

4. การบันทึกข้อมูลการตรวจสอบ


function logger($txt, $path = null) {
    $log_file = $path ?? "log.txt";
    $myfile = fopen($log_file, "a") or die("Unable to open file!");
    fwrite($myfile, "\n" . $txt);
    fclose($myfile);
}

ฟังก์ชัน logger() ใช้ในการบันทึกผลการยืนยันลายเซ็น เช่น "Signature is valid." หรือ "Signature is invalid." ลงในไฟล์ log(ไฟล์ log แบบประหยัดอ่ะครับ🤣)

5. การจัดการคำขอ POST


if (isset($_POST)) {
    try {
        $payload = file_get_contents('php://input');
        $headers = get_ds_headers();
        if (array_key_exists("VerificationSignature", $headers)) {
            $verificationSignature = $headers["VerificationSignature"];
            $verifyResult = certificate('https://api.m-pay.com.au', $verificationSignature, $payload);

            if ($verifyResult === 1) {
                // coding...
                logger("Signature is valid.");
            } elseif ($verifyResult === 0) {
                logger("Signature is invalid.");
            } else {
                logger("Error verifying signature: " . openssl_error_string());
            }
        }
    } catch (Exception $e) {
        logger("\nException: " . $e->getMessage() . "\n");
    }
    header("HTTP/1.1 200 OK");
}

โค้ดส่วนนี้ใช้ในการจัดการคำขอ POST ที่เข้ามา

  1. ตรวจสอบว่าเป็นคำขอ POST: ตรวจสอบว่ามีข้อมูลส่งเข้ามาหรือไม่
  2. ดึง Payload และ Headers: ดึงข้อมูล Payload และ headers ของคำขอ
  3. ยืนยันลายเซ็น: หากมี Verification Signature อยู่ใน headers จะใช้ฟังก์ชัน certificate() เพื่อตรวจสอบลายเซ็น
  4. บันทึกผลลัพธ์: บันทึกผลลัพธ์การตรวจสอบลายเซ็นลงในไฟล์ log
  5. ส่งกลับสถานะ 200 OK: หากทุกอย่างผ่านไปด้วยดี ระบบจะส่งกลับสถานะ 200 OK

สรุป

การยืนยันลายเซ็น Webhook ด้วย PHP เป็นกระบวนการที่สำคัญเพื่อให้แน่ใจว่าข้อมูลที่ได้รับมามีความถูกต้องและปลอดภัย การใช้ฟังก์ชันตามที่ได้อธิบายข้างต้นนี้จะช่วยให้การตรวจสอบลายเซ็นเป็นไปอย่างมีประสิทธิภาพ