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

ผู้ขายสามารถใช้การยืนยันการชำระเงินที่ปลอดภัย (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 จึงสามารถบอก ผู้ขายที่ทำธุรกรรมเสร็จสมบูรณ์

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