メインコンテンツへスキップ

3D Secure

3D Secure 2.0認証を実装して、不正を削減し、責任を転嫁し、ヨーロッパなどでのStrong Customer Authentication (SCA)要件に準拠します。

概要

3D Secure (3DS)は、オンラインカード取引にセキュリティレイヤーを追加する認証プロトコルです。有効にすると、顧客は決済を完了する前にカード発行者で本人確認を行います。

主な利点:

  • 🔒 不正の削減 - 追加の認証ステップ
  • 🛡️ 責任の転嫁 - 不正の責任がカード発行者に転嫁されます
  • SCA準拠 - ヨーロッパの決済に必要
  • 📈 承認率の向上 - 発行者は認証された取引を信頼します
  • 💳 すべてのカードをサポート - Visa、Mastercard、JCB

3D Secureブランド:

  • Visa: Visa Secure (旧Verified by Visa)
  • Mastercard: Mastercard Identity Check (旧Mastercard SecureCode)
  • JCB: J/Secure

3D Secure 1 vs 3D Secure 2

機能3DS 1.0 (レガシー)3DS 2.0 (現在)
ユーザー体験ポップアップ、扱いにくいアプリ内、シームレス
モバイルサポート貧弱優秀
共有データ限定的リッチなコンテキスト
摩擦高い低い (多くの場合摩擦なし)
認証パスワード生体認証、PIN、OTP
成功率低い高い
備考

Omiseはデフォルトで3D Secure 2.0をサポートしており、最高のユーザー体験と最高の承認率を提供します。

3D Secureの仕組み

顧客体験:

  1. 顧客がチェックアウト時にカード情報を入力
  2. 3DSが必要な場合、発行者の認証ページにリダイレクト
  3. 顧客が以下で認証:
    • 生体認証 (指紋、Face ID)
    • PINまたはパスワード
    • ワンタイムパスワード (SMS/アプリ)
  4. マーチャントサイトに戻る
  5. 認証に基づいて決済が完了または失敗

完了時間: 10-30秒 (生体認証でシームレス)

実装

自動3DS (推奨)

Omiseは必要に応じて自動的に3DSをトリガーします:

const omise = require('omise')({
publicKey: 'pkey_test_YOUR_PUBLIC_KEY',
secretKey: 'skey_test_YOUR_SECRET_KEY'
});

// カードトークンで課金を作成
const charge = await omise.charges.create({
amount: 100000,
currency: 'THB',
card: cardToken, // Omise.jsから
return_uri: 'https://yourdomain.com/payment/callback'
});

// 3DSが必要かどうかを確認
if (charge.authorize_uri) {
// 顧客を3DS認証にリダイレクト
res.redirect(charge.authorize_uri);
} else if (charge.status === 'successful') {
// 3DSなしで決済成功
res.redirect('/success');
}

3DSからの復帰を処理

app.get('/payment/callback', async (req, res) => {
try {
const chargeId = req.query.charge_id;
const charge = await omise.charges.retrieve(chargeId);

if (charge.status === 'successful') {
// 3DS認証成功
await processOrder(charge.metadata.order_id);
res.redirect('/payment-success');
} else if (charge.status === 'failed') {
// 認証または決済失敗
res.redirect(`/payment-failed?reason=${charge.failure_message}`);
} else {
// 保留中 (まれ)
res.redirect('/payment-pending');
}
} catch (error) {
res.redirect('/payment-error');
}
});

3DSが必要な場合

必須 (常に必要)

欧州経済領域 (EEA):

  • すべての消費者決済にはStrong Customer Authentication (SCA)が必要
  • EU + アイスランド、リヒテンシュタイン、ノルウェーをカバー
  • マーチャントは3DSを実装する必要があります。そうしないとカードが拒否されます

一部の銀行/地域:

  • インド (RBI義務)
  • アジア太平洋の一部
  • 発行者のポリシーによって異なります

オプション (リスクベース)

カード発行者が3DSを要求する可能性がある場合:

  • 高額取引
  • 高リスクマーチャント
  • 疑わしいパターン
  • マーチャントでの顧客の初回取引
  • 国境を越えた決済

摩擦なし vs チャレンジ:

  • 摩擦なし: 発行者が顧客のアクションなしで承認 (3DS 2.0の80%以上)
  • チャレンジ: 顧客が認証する必要がある (20%)

完全な実装例

const express = require('express');
const omise = require('omise')({
publicKey: process.env.OMISE_PUBLIC_KEY,
secretKey: process.env.OMISE_SECRET_KEY
});

const app = express();
app.use(express.json());

// ステップ1: 課金を作成
app.post('/checkout', async (req, res) => {
try {
const { token, amount, currency, order_id } = req.body;

const charge = await omise.charges.create({
amount: amount,
currency: currency,
card: token, // Omise.jsから
return_uri: `${process.env.BASE_URL}/payment/callback`,
metadata: {
order_id: order_id
}
});

if (charge.authorize_uri) {
// 3DS必要 - リダイレクトURLを返す
res.json({
requires_authentication: true,
authorize_uri: charge.authorize_uri,
charge_id: charge.id
});
} else if (charge.status === 'successful') {
// 3DSなしで成功
await processOrder(order_id);
res.json({
requires_authentication: false,
status: 'successful',
charge_id: charge.id
});
} else {
// 失敗
res.status(400).json({
error: charge.failure_message
});
}

} catch (error) {
res.status(500).json({ error: error.message });
}
});

// ステップ2: 3DS復帰を処理
app.get('/payment/callback', async (req, res) => {
try {
const charge = await omise.charges.retrieve(req.query.charge_id);

if (charge.status === 'successful') {
await processOrder(charge.metadata.order_id);
res.redirect(`/order-confirmation?order=${charge.metadata.order_id}`);
} else {
res.redirect(`/payment-failed?error=${charge.failure_code}`);
}
} catch (error) {
res.redirect('/payment-error');
}
});

// ステップ3: Webhook (推奨)
app.post('/webhooks/omise', async (req, res) => {
const event = req.body;

if (event.key === 'charge.complete') {
const charge = event.data;

if (charge.status === 'successful') {
await processOrder(charge.metadata.order_id);
}
}

res.sendStatus(200);
});

app.listen(3000);

テスト3D Secure

テストカード

カード番号3DS動作結果
42424242424242423DSなし成功
40000000000032203DS必要、成功成功
40000000000092353DS必要、失敗拒否
40000082600031783DS、残高不足拒否

テストフロー

  1. 3DSテストカードを使用
  2. テスト3DSページにリダイレクト
  3. "成功"または"失敗"ボタンをクリック
  4. 結果とともにreturn_uriに戻る

完全なリストについてはテストガイドをご覧ください。

ベストプラクティス

1. 常にreturn_uriを提供

// 3DSリダイレクトに必要
const charge = await omise.charges.create({
// ... その他のパラメータ
return_uri: 'https://yourdomain.com/payment/callback' // HTTPSである必要があります
});

2. すべての課金ステータスを処理

switch (charge.status) {
case 'successful':
// 決済完了
break;
case 'failed':
// エラーを表示、再試行を許可
break;
case 'pending':
// Webhookを待つ (まれ)
break;
case 'expired':
// 顧客が3DSを完了しなかった
break;
}

3. HTTPSを使用

3DSはreturn_uriにHTTPSが必要です:

✅ https://yourdomain.com/callback
❌ http://yourdomain.com/callback

4. Webhookを実装

return_uriのみに依存しないでください:

// Webhookは信頼できる情報源です
app.post('/webhooks/omise', handleWebhook);

// Return URIは顧客UXのみ
app.get('/payment/callback', showCustomerResult);

よくある質問

3D Secureは必須ですか?

必須の場合:

  • 欧州経済領域 (EEA)の決済 - SCA要件
  • インド - RBI義務
  • 一部のアジア太平洋地域

オプションの場合:

  • その他の地域 (ただし不正保護のために推奨)
  • 高リスク取引 (発行者が要求する場合があります)
3DSはコンバージョンを下げますか?

3DS 1.0: はい、大幅な低下 (10-20%) 3DS 2.0: 最小限の影響 (1-5%) 理由:

  • 摩擦なし認証 (80%以上のケース)
  • 生体認証 (高速で簡単)
  • より良いモバイル体験
責任転嫁とは何ですか?

3DS認証が成功すると、不正の責任はマーチャントからカード発行者に転嫁されます。3DSがない場合、マーチャントが不正の責任を負います。

顧客は3DSをスキップできますか?

いいえ。3DSが必要な場合(規制または発行者による)、スキップできません。顧客が認証を完了しない場合、決済は失敗します。

関連リソース

次のステップ

  1. 統合に自動3DSを実装
  2. すべてのカード課金にreturn_uriを追加
  3. 3DSリダイレクトと復帰フローを処理
  4. 3DSテストカードでテスト
  5. Webhook処理を設定
  6. 3DS成功率を監視
  7. 本番環境に移行