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

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

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

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

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

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

  1. ลูกค้าให้ข้อมูลเข้าสู่ระบบการชำระเงิน (เช่น ข้อมูลบัตรเครดิต) แก่ผู้ขาย
  2. ผู้ขายถามผู้ออกหรือธนาคารที่เกี่ยวข้องของข้อมูลเข้าสู่ระบบการชำระเงิน (ฝ่ายหรือ RP) หากผู้ชำระเงินต้องการการตรวจสอบสิทธิ์แยกต่างหาก เช่น Exchange นี้อาจเกิดขึ้นกับ 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 จะบอกผู้ขายได้ว่าธุรกรรมเสร็จสมบูรณ์

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