ตรวจสอบสิทธิ์ด้วยการยืนยันการชำระเงินที่ปลอดภัย

ผู้ขายสามารถใช้การยืนยันการชำระเงินที่ปลอดภัย (SPC) เป็นส่วนหนึ่งของกระบวนการยืนยันตัวตนลูกค้าแบบขั้นสูง (SCA) สำหรับบัตรเครดิตหรือบัญชีธนาคารหนึ่งๆ WebAuthn จะดำเนินการตรวจสอบสิทธิ์ (มักจะผ่านข้อมูลไบโอเมตริก) คุณต้องลงทะเบียน WebAuthn ล่วงหน้า ซึ่งคุณสามารถดูข้อมูลได้ในลงทะเบียนการยืนยันการชำระเงินที่ปลอดภัย

วิธีการทํางานของการติดตั้งใช้งานทั่วไป

การใช้งาน SPC ที่พบบ่อยที่สุดคือเมื่อลูกค้าทำการซื้อในเว็บไซต์ของผู้ขาย และผู้ออกบัตรเครดิตหรือธนาคารกำหนดให้มีการยืนยันตัวตนผู้ชำระเงิน

เวิร์กโฟลว์การตรวจสอบสิทธิ์

มาดูขั้นตอนการตรวจสอบสิทธิ์กัน

  1. ลูกค้าให้ข้อมูลเข้าสู่ระบบการชำระเงิน (เช่น ข้อมูลบัตรเครดิต) แก่ผู้ขาย
  2. ผู้ขายจะสอบถามผู้ออกบัตรหรือธนาคารที่เกี่ยวข้อง (บุคคลที่เชื่อถือหรือ RP) ของข้อมูลเข้าสู่ระบบการชำระเงินว่าผู้ชำระเงินต้องการตรวจสอบสิทธิ์แยกต่างหากหรือไม่ การเปลี่ยนรหัสนี้อาจเกิดขึ้นได้ เช่น กับ EMV® 3-D Secure
    • หาก RP ต้องการให้ผู้ขายใช้ SPC และหากผู้ใช้เคยลงทะเบียนไว้ก่อนหน้านี้ RP จะตอบกลับพร้อมรายการรหัสข้อมูลเข้าสู่ระบบที่ลงทะเบียนโดยผู้ชำระเงินและคำถาม
    • หากไม่จําเป็นต้องตรวจสอบสิทธิ์ ผู้ขายจะดําเนินธุรกรรมให้เสร็จสมบูรณ์ได้
  3. หากจำเป็นต้องมีการตรวจสอบสิทธิ์ ผู้ขายจะพิจารณาว่าเบราว์เซอร์รองรับ SPC หรือไม่
    • หากเบราว์เซอร์ไม่รองรับ SPC ให้ดำเนินการตามขั้นตอนการตรวจสอบสิทธิ์ที่มีอยู่
  4. ผู้ขายเรียกใช้ SPC เบราว์เซอร์จะแสดงกล่องโต้ตอบการยืนยัน
    • หากไม่มีรหัสข้อมูลเข้าสู่ระบบที่ส่งมาจาก RP ให้กลับไปใช้ขั้นตอนการตรวจสอบสิทธิ์ที่มีอยู่ หลังจากตรวจสอบสิทธิ์สำเร็จแล้ว ให้พิจารณาใช้การลงทะเบียน SPC เพื่อปรับปรุงการตรวจสอบสิทธิ์ในอนาคต
  5. ผู้ใช้ยืนยันและตรวจสอบสิทธิ์จำนวนเงินและปลายทางของการชำระเงินโดยการปลดล็อกอุปกรณ์
  6. ผู้ขายจะได้รับข้อมูลเข้าสู่ระบบจากการตรวจสอบสิทธิ์
  7. RP ได้รับข้อมูลเข้าสู่ระบบจากผู้ขายและยืนยันความถูกต้อง
  8. RP จะส่งผลการยืนยันไปยังผู้ขาย
  9. ผู้ขายจะแสดงข้อความให้ผู้ใช้เพื่อระบุว่าการชำระเงินสำเร็จหรือไม่

การตรวจหาองค์ประกอบ

หากต้องการทราบว่าเบราว์เซอร์รองรับ SPC หรือไม่ คุณสามารถส่งการเรียกจำลองไปยัง canMakePayment()

คัดลอกและวางโค้ดต่อไปนี้เพื่อตรวจหา SPC ในเว็บไซต์ของผู้ขาย

const isSecurePaymentConfirmationSupported = async () => {
  if (!'PaymentRequest' in window) {
    return [false, 'Payment Request API is not supported'];
  }

  try {
    // The data below is the minimum required to create the request and
    // check if a payment can be made.
    const supportedInstruments = [
      {
        supportedMethods: "secure-payment-confirmation",
        data: {
          // RP's hostname as its ID
          rpId: 'rp.example',
          // A dummy credential ID
          credentialIds: [new Uint8Array(1)],
          // A dummy challenge
          challenge: new Uint8Array(1),
          instrument: {
            // Non-empty display name string
            displayName: ' ',
            // Transparent-black pixel.
            icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==',
          },
          // A dummy merchant origin
          payeeOrigin: 'https://non-existent.example',
        }
      }
    ];

    const details = {
      // Dummy shopping details
      total: {label: 'Total', amount: {currency: 'USD', value: '0'}},
    };

    const request = new PaymentRequest(supportedInstruments, details);
    const canMakePayment = await request.canMakePayment();
    return [canMakePayment, canMakePayment ? '' : 'SPC is not available'];
  } catch (error) {
    console.error(error);
    return [false, error.message];
  }
};

isSecurePaymentConfirmationSupported().then(result => {
  const [isSecurePaymentConfirmationSupported, reason] = result;
  if (isSecurePaymentConfirmationSupported) {
    // Display the payment button that invokes SPC.
  } else {
    // Fallback to the legacy authentication method.
  }
});

ตรวจสอบสิทธิ์ผู้ใช้

หากต้องการตรวจสอบสิทธิ์ผู้ใช้ ให้เรียกใช้เมธอด PaymentRequest.show() พร้อมพารามิเตอร์ secure-payment-confirmation และ WebAuthn ดังนี้

พารามิเตอร์ที่คุณควรระบุให้กับพร็อพเพอร์ตี้ data ของวิธีการชำระเงิน SecurePaymentConfirmationRequest มีดังนี้

พารามิเตอร์ คำอธิบาย
rpId ชื่อโฮสต์ของต้นทาง RP เป็นรหัส RP
challenge คำถามแบบสุ่มที่ป้องกันการโจมตีแบบเล่นซ้ำ
credentialIds อาร์เรย์รหัสข้อมูลเข้าสู่ระบบ ในการตรวจสอบสิทธิ์ของ WebAuthn พร็อพเพอร์ตี้ allowCredentials จะยอมรับอาร์เรย์ของออบเจ็กต์ PublicKeyCredentialDescriptor แต่ใน SPC คุณจะส่งเฉพาะรายการรหัสข้อมูลเข้าสู่ระบบเท่านั้น
payeeName (ไม่บังคับ) ชื่อผู้รับเงิน
payeeOrigin ต้นทางของผู้รับเงิน ในสถานการณ์ข้างต้น ต้นทางคือต้นทางของผู้ขาย
instrument สตริงสำหรับ displayName และ URL สำหรับ icon ที่ชี้ไปยังทรัพยากรรูปภาพ บูลีนที่ไม่บังคับ (ค่าเริ่มต้นคือ true) สำหรับ iconMustBeShown ที่ระบุว่าต้องดึงข้อมูลไอคอนและแสดงไอคอนให้เสร็จสมบูรณ์เพื่อให้คำขอสำเร็จ
timeout ระยะหมดเวลาในการลงนามธุรกรรมเป็นมิลลิวินาที
extensions เพิ่มส่วนขยายลงในคอล WebAuthn คุณไม่จำเป็นต้องระบุส่วนขยาย "การชำระเงิน" ด้วยตนเอง

ดูโค้ดตัวอย่างนี้

// After confirming SPC is available on this browser via a feature detection,
// fetch the request options cross-origin from the RP server.
const options = fetchFromServer('https://rp.example/spc-auth-request');
const { credentialIds, challenge } = options;

const request = new PaymentRequest([{
  // Specify `secure-payment-confirmation` as payment method.
  supportedMethods: "secure-payment-confirmation",
  data: {
    // The RP ID
    rpId: 'rp.example',

    // List of credential IDs obtained from the RP server.
    credentialIds,

    // The challenge is also obtained from the RP server.
    challenge,

    // A display name and an icon that represent the payment instrument.
    instrument: {
      displayName: "Fancy Card ****1234",
      icon: "https://rp.example/card-art.png",
      iconMustBeShown: false
    },

    // The origin of the payee (merchant)
    payeeOrigin: "https://merchant.example",

    // The number of milliseconds to timeout.
    timeout: 360000,  // 6 minutes
  }
}], {
  // Payment details.
  total: {
    label: "Total",
    amount: {
      currency: "USD",
      value: "5.00",
    },
  },
});

try {
  const response = await request.show();

  // response.details is a PublicKeyCredential, with a clientDataJSON that
  // contains the transaction data for verification by the issuing bank.
  // Make sure to serialize the binary part of the credential before
  // transferring to the server.
  const result = fetchFromServer('https://rp.example/spc-auth-response', response.details);
  if (result.success) {
    await response.complete('success');
  } else {
    await response.complete('fail');
  }
} catch (err) {
  // SPC cannot be used; merchant should fallback to traditional flows
  console.error(err);
}

ฟังก์ชัน .show() จะแสดงผลเป็นออบเจ็กต์ PaymentResponse ยกเว้น details ที่มีข้อมูลเข้าสู่ระบบคีย์สาธารณะซึ่งมี clientDataJSON ที่มีข้อมูลธุรกรรม (payment) สำหรับการยืนยันโดย RP

ข้อมูลเข้าสู่ระบบที่ได้ต้องได้รับการโอนข้ามแหล่งที่มาไปยัง RP และได้รับการยืนยัน

วิธีที่ RP ยืนยันธุรกรรม

การยืนยันข้อมูลธุรกรรมที่เซิร์ฟเวอร์ RP เป็นขั้นตอนสําคัญที่สุดในกระบวนการชําระเงิน

หากต้องการยืนยันข้อมูลธุรกรรม RP สามารถทําตามกระบวนการยืนยันการยืนยันการตรวจสอบสิทธิ์ของ WebAuthn นอกจากนี้ ยังต้องยืนยัน payment ด้วย

ตัวอย่างเพย์โหลดของ clientDataJSON

{
  "type":"payment.get",
  "challenge":"SAxYy64IvwWpoqpr8JV1CVLHDNLKXlxbtPv4Xg3cnoc",
  "origin":"https://spc-merchant.glitch.me",
  "crossOrigin":false,
  "payment":{
    "rp":"spc-rp.glitch.me",
    "topOrigin":"https://spc-merchant.glitch.me",
    "payeeOrigin":"https://spc-merchant.glitch.me",
    "total":{
      "value":"15.00",
      "currency":"USD"
    },
    "instrument":{
      "icon":"https://cdn.glitch.me/94838ffe-241b-4a67-a9e0-290bfe34c351%2Fbank.png?v=1639111444422",
      "displayName":"Fancy Card 825809751248"
    }
  }
}
  • rp ตรงกับต้นทางของ RP
  • topOrigin ตรงกับต้นทางระดับบนสุดที่ RP คาดหวัง (ต้นทางของผู้ขายในตัวอย่างด้านบน)
  • payeeOrigin ตรงกับต้นทางของผู้รับเงินที่ควรจะแสดงต่อผู้ใช้
  • total ตรงกับจํานวนเงินธุรกรรมที่ควรแสดงต่อผู้ใช้
  • instrument ตรงกับรายละเอียดเครื่องมือการชำระเงินที่ควรแสดงต่อผู้ใช้
const clientData = base64url.decode(response.clientDataJSON);
const clientDataJSON = JSON.parse(clientData);

if (!clientDataJSON.payment) {
  throw 'The credential does not contain payment payload.';
}

const payment = clientDataJSON.payment;
if (payment.rp !== expectedRPID ||
    payment.topOrigin !== expectedOrigin ||
    payment.payeeOrigin !== expectedOrigin ||
    payment.total.value !== '15.00' ||
    payment.total.currency !== 'USD') {
  throw 'Malformed payment information.';
}

หลังจากผ่านเกณฑ์การยืนยันทั้งหมดแล้ว RP สามารถแจ้งให้ผู้ขายทราบว่าธุรกรรมเสร็จสมบูรณ์

ขั้นตอนถัดไป