Xác thực bằng xác nhận thanh toán an toàn

Người bán có thể sử dụng phương thức Xác nhận thanh toán an toàn (SPC) trong quy trình xác thực khách hàng nghiêm ngặt (SCA) đối với một thẻ tín dụng hoặc tài khoản ngân hàng cụ thể. WebAuthn thực hiện việc xác thực (thường là thông qua hệ thống nhận dạng sinh trắc học). WebAuthn phải được đăng ký trước. Bạn có thể tìm hiểu về việc này trong bài viết Đăng ký một xác nhận thanh toán an toàn.

Cách hoạt động của quy trình triển khai thông thường

Trường hợp sử dụng phổ biến nhất của SPC là khi khách hàng mua hàng trên trang web của người bán và tổ chức phát hành thẻ tín dụng hoặc ngân hàng yêu cầu xác thực người thanh toán.

Quy trình xác thực.

Hãy cùng tìm hiểu quy trình xác thực:

  1. Khách hàng cung cấp thông tin thanh toán của họ (chẳng hạn như thông tin thẻ tín dụng) cho người bán.
  2. Người bán hỏi ngân hàng hoặc tổ chức phát hành thông tin thanh toán tương ứng (bên tin cậy hoặc bên bị hạn chế) trong trường hợp người thanh toán cần một phương thức xác thực riêng. Chẳng hạn, quá trình trao đổi này có thể xảy ra với EMV® 3-D Secure.
    • Nếu RP muốn người bán sử dụng SPC và nếu người dùng đã đăng ký trước đó, thì RP sẽ phản hồi bằng danh sách mã thông tin xác thực mà người thanh toán đã đăng ký và đưa ra một thử thách.
    • Nếu không cần xác thực, người bán có thể tiếp tục hoàn tất giao dịch.
  3. Nếu cần xác thực, người bán sẽ xác định xem trình duyệt có hỗ trợ SPC hay không.
    • Nếu trình duyệt không hỗ trợ SPC, hãy tiếp tục quy trình xác thực hiện có.
  4. Người bán gọi SPC. Trình duyệt sẽ hiển thị hộp thoại xác nhận.
    • Nếu không có mã thông tin xác thực nào được chuyển từ RP, hãy quay lại quy trình xác thực hiện có. Sau khi xác thực thành công, hãy cân nhắc sử dụng đăng ký SPC để đơn giản hoá quy trình xác thực trong tương lai.
  5. Người dùng xác nhận và xác thực số tiền cũng như đích đến của khoản thanh toán bằng cách mở khoá thiết bị.
  6. Người bán nhận được thông tin xác thực qua quá trình xác thực.
  7. RP nhận thông tin xác thực từ người bán và xác minh tính xác thực của thông tin đó.
  8. Bên bị hạn chế gửi kết quả xác minh cho người bán.
  9. Người bán sẽ hiển thị cho người dùng thông báo cho biết giao dịch thanh toán có thành công hay không.

Phát hiện tính năng

Để biết trình duyệt có hỗ trợ SPC hay không, bạn có thể gửi một lệnh gọi giả đến canMakePayment().

Sao chép và dán mã sau đây để tính năng phát hiện SPC trên trang web của người bán.

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.
  }
});

Xác thực người dùng

Để xác thực người dùng, hãy gọi phương thức PaymentRequest.show() bằng các tham số secure-payment-confirmation và WebAuthn:

Dưới đây là các thông số bạn cần cung cấp cho thuộc tính data của phương thức thanh toán, SecurePaymentConfirmationRequest.

Thông số Nội dung mô tả
rpId Tên máy chủ của nguồn gốc RP là mã nhận dạng bên bị hạn chế.
challenge Thử thách ngẫu nhiên ngăn chặn các cuộc tấn công phát lại.
credentialIds Một mảng mã nhận dạng thông tin xác thực. Trong phương thức xác thực của WebAuthn, thuộc tính allowCredentials chấp nhận một mảng các đối tượng PublicKeyCredentialDescriptor, nhưng trong SPC, bạn chỉ truyền danh sách mã nhận dạng thông tin xác thực.
payeeName (không bắt buộc) Tên người nhận thanh toán.
payeeOrigin Nguồn gốc của người nhận thanh toán. Trong trường hợp đã đề cập ở trên, đó là nguồn gốc của người bán.
instrument Một chuỗi cho displayName và một URL cho icon trỏ đến một tài nguyên hình ảnh. Giá trị boolean không bắt buộc (mặc định là true) cho iconMustBeShown chỉ định một biểu tượng phải được tìm nạp và hiển thị thành công để yêu cầu thành công.
timeout Thời gian chờ để ký giao dịch tính bằng mili giây
extensions Các tiện ích được thêm vào lệnh gọi WebAuthn. Bạn không phải tự chỉ định thời gian gia hạn "thanh toán".

Xem mã ví dụ này:

// 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);
}

Hàm .show() dẫn đến đối tượng PaymentResponse, ngoại trừ details chứa thông tin xác thực khoá công khai với clientDataJSON chứa dữ liệu giao dịch (payment) để RP xác minh.

Thông tin đăng nhập thu được phải được chuyển trên nhiều nguồn gốc sang RP và được xác minh.

Cách bên bị hạn chế xác minh giao dịch

Việc xác minh dữ liệu giao dịch tại máy chủ RP là bước quan trọng nhất trong quy trình thanh toán.

Để xác minh dữ liệu giao dịch, bên bị hạn chế có thể tuân theo quy trình xác minh câu nhận định xác thực của WebAuthn. Ngoài ra, họ cần xác minh payment.

Một tải trọng mẫu của 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 khớp với nguồn gốc của RP.
  • topOrigin khớp với nguồn gốc cấp cao nhất mà RP dự kiến (nguồn gốc của người bán trong ví dụ trên).
  • payeeOrigin khớp với nguồn gốc của người nhận thanh toán đã hiển thị cho người dùng.
  • total khớp với số tiền giao dịch cần được hiển thị cho người dùng.
  • instrument khớp với thông tin chi tiết về phương thức thanh toán đã hiển thị cho người dùng.
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.';
}

Sau khi tất cả các tiêu chí xác minh đã được vượt qua, bên bị hạn chế có thể cho người bán biết rằng giao dịch đã thành công.

Các bước tiếp theo