決済を行う
このページで扱うトピック
Omise.jsを使ったカード情報の収集
このガイドでは、自社サイト上のページから直接カード情報を収集し、トークン化するためのフォームの作り方を説明します。
Omise.jsを使えば、カード情報の収集を簡単に行えます。Omise.jsは、顧客のブラウザ上で独自のHTMLフォームを実行できるクライアントサイドのJavaScriptライブラリです。機密性の高いカードデータをOmiseサーバーへ送信し、その代わりにカードトークンを受け取ります。そのトークンを自社サーバーへ転送して処理を行うため、自社サーバーが機密性の高いカード情報を直接扱う必要はありません。
このガイドは、カード情報の収集とトークン化に特化しています。Omise.jsはカード以外の決済方法(PromptPay、GrabPay、その他のsource)にも対応しており、独自フォームの代わりに利用できる構築済みの決済ウィジェットも提供しています。いずれかについて知りたい場合は、Omise.jsの総合リファレンスをご覧ください。
カードデータをOmiseへ送信する際にサポートされている唯一の方法は、Omise.jsを使ったJavaScript経由での送信です。ただし、貴社がサーバーサイドでのカードデータ処理を許可するPCI-DSSライセンスを保有している場合を除きます。
要件: チェックアウトページはHTTPSで配信する必要があります。Omise.jsは、通常のHTTPで配信されたページでは動作しません。チェックアウトページだけでなく、サイト全体でHTTPSを有効にすることをOmiseは推奨します。(出典: docs.omise.co/omise-js)

仕組み
大まかな流れは次のとおりです。
- Omise.jsと公開鍵を使用して、顧客のブラウザからOmiseへカード保有者のデータを送信します。
- Omiseのトークンサービスが、一回限り使用可能なカードトークンを返します。
- そのトークンを自社サーバーへ転送します。
- トークンを使ってカードに対する操作を実行します。カードにchargeを行う、新規顧客としてカードを保存する、または既存の顧客にカードを追加することができます。
トークンを保存しておくことはOmiseとして推奨していません。一回限りの使用を前提としているため、後で使うために保存しておくメリットはありません。使用したらすぐに破棄してください。
試してみる: Omiseトークンシミュレーター
トークンAPIについて詳しくは、トークンリファレンスをご覧ください。
実装例
まず、Omise.jsをWebページに組み込みます。</body>の閉じタグの直前に追加してください。
<script src="https://cdn.omise.co/omise.js"></script>
Omise.jsライブラリ自体はjQueryを必要としませんが、この例ではDOM操作を簡単に行うためにjQueryを使用しています。jQueryへの依存を避けたい場合は、同じフォーム送信・DOM参照のロジックをバニラJavaScriptで書くこともできます。
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
次に、Omise.jsがOmise APIに対して認証を行えるよう、公開鍵を追加します。
<script>
Omise.setPublicKey("pkey_test_5yx6s4dmon2i23pwaxw");
</script>
次に、カード情報を収集するフォームを作成します。
<form action="/checkout" method="post" id="checkout">
<div id="token_errors"></div>
<input type="hidden" name="omise_token">
<div>
Name<br>
<input type="text" data-omise="holder_name">
</div>
<div>
Number<br>
<input type="text" data-omise="number">
</div>
<div>
Date<br>
<input type="text" data-omise="expiration_month" size="4"> /
<input type="text" data-omise="expiration_year" size="8">
</div>
<div>
Security Code<br>
<input type="text" data-omise="security_code" size="8">
</div>
<input type="submit" id="create_token">
</form>
次に、送信ボタンが押されたときにトークンの生成をトリガーします。成功した場合は、トークンフィールドに値を設定し、機密性の高いフィールドをクリアして、自社サーバーへ送信されないようにします。
$("#checkout").submit(function () {
var form = $(this);
// 送信ボタンを無効化し、連続クリックを防ぐ。
form.find("input[type=submit]").prop("disabled", true);
// フォームの入力値を、有効なcardオブジェクトへ変換する。
var card = {
"name": form.find("[data-omise=holder_name]").val(),
"number": form.find("[data-omise=number]").val(),
"expiration_month": form.find("[data-omise=expiration_month]").val(),
"expiration_year": form.find("[data-omise=expiration_year]").val(),
"security_code": form.find("[data-omise=security_code]").val()
};
// トークン作成のリクエストを送信し、Omiseからレスポンスを受け取った
// タイミングでコールバック関数を実行する。
//
// レスポンスがエラーである可能性があるため、コールバック内で
// 適切に処理する必要がある。
Omise.createToken("card", card, function (statusCode, response) {
if (!response || response.object == "error") {
// エラーメッセージを表示する。
var message_text = (response && response.message) ? response.message : "Unable to generate a token. Check your connection and try again.";
$("#token_errors").html(message_text);
// 送信ボタンを再度有効化する。
form.find("input[type=submit]").prop("disabled", false);
} else {
// omise_tokenフィールドに値を設定する。
form.find("[name=omise_token]").val(response.id);
// カード番号とセキュリティコードをフォームから削除してから、
// サーバーへ送信する。
form.find("[data-omise=number]").val("");
form.find("[data-omise=security_code]").val("");
// トークンをサーバーへ送信する。
form.get(0).submit();
}
});
// 生のカードデータのままフォームが送信されるのを防ぐ。
return false;
});
以上です。Omise.jsがクレジットカード情報を収集し、トークンを返します。そのトークンを使って、カードに対する操作を行うことができます。
補足: 2020年4月1日以降、Omiseはトークン・カードAPIのレスポンスにおいて、security_code_checkを常にtrueとして固定的に返すようにしています。これは、CVVのブルートフォース攻撃を防ぐための意図的な対応です。以前の例で行っていたこのチェックは、この変更以降は意味を持ちません。エラー処理はresponse.object == "error"(同等の代替としてstatusCode !== 200)のみに依存すべきです。このガイドのコード例でも、レスポンス自体が存在しない場合(リクエストがレスポンスを受け取る前に失敗した場合など)に備えたガードを追加しています。カードの実際の有効性は、トークン作成時点ではなく、そのトークンを使ってchargeを作成する時点で判断されます。(出典: docs.omise.co/protecting-you-against-fraudsters)
よくある質問
自社サーバーが生のカードデータを見ることはありますか? いいえ。カードデータは顧客のブラウザからOmise.jsを通じて直接Omiseへ送信されます。自社サーバーが受け取るのは生成されたトークンのみであり、カード番号、有効期限、セキュリティコードを受け取ることはありません。
トークンは後で使うために保存すべきですか? いいえ。トークンは一回限りの使用を前提としています。カードへのcharge、顧客への保存、既存顧客への追加のいずれかにトークンを使用した時点で、その役目は終わっています。すぐに使用して破棄してください。保存しておくメリットはありません。
公開鍵(pkey_test_... / pkey_...)をクライアントサイドのJavaScriptに公開しても安全ですか?
基本的には安全ですが、「公開しても安全」であることは「リスクがゼロ」であることを意味しません。公開鍵はクライアントサイドでの利用を想定して設計されており、トークンとsourceの作成に用途が限定されているため、charge作成や資金移動、秘密鍵が必要なあらゆる操作を行うことはできません。ただし、Omiseは公開鍵の露出を悪用した実際の攻撃事例を報告しています。盗まれたカード番号と組み合わせることで、公開鍵を使ってトークン作成リクエストを繰り返し送信し、レスポンスのsecurity_code_checkフィールドを確認することで、カードのCVVをブルートフォース攻撃で割り出すことが以前は可能でした。Omiseは2020年4月1日、security_code_checkを常にtrueとして固定的に返すようにすることで、この脆弱性を解消しました。つまり、鍵そのものが資金を動かすことはできませんが、盗まれたカードデータと組み合わされた公開鍵は、依然としてカードテスト・列挙型の攻撃に悪用され得ます。Omiseが鍵のスコープ制限に加えて、事前オーソリ、IPジオロケーション、行動分析による不正検知を重ねて実施しているのは、こうした理由からです。(出典: docs.omise.co/protecting-you-against-fraudsters、docs.omise.co/api-authentication)
Omise.jsの利用にjQueryは必要ですか? いいえ。これらの例でjQueryを使用しているのは、DOM操作やフォーム送信イベントの処理を簡単に行うための利便性のためです。Omise.js自体はjQueryに依存しておらず、同じロジックをバニラJavaScriptで書くこともできます。
response.object == "error"のとき、response.codeには実際にどのような値が入りますか?
このガイドのコード例ではエラーの発生を確認していますが、その原因までは列挙していません。トークン作成時に返される主なコードは次のとおりです。
| コード | 内容 |
|---|---|
invalid_card |
カードのいずれかの項目が検証に失敗しました。 |
expired_card |
カードの有効期限が過去の日付です。 |
invalid_security_code |
入力されたCVV・セキュリティコードが無効です。 |
authentication_failure |
公開鍵が指定されていない、無効である、またはアクセス権限が不足しています。 |
service_not_found |
アカウントでカード決済が有効になっていません。 |
正確な値はresponse.codeを、顧客に表示する人が読める説明はresponse.messageをご確認ください。完全なリストはAPIエラーリファレンスをご覧ください。
未使用のトークンの有効期限はどのくらいですか? トークンは一回限りの使用を前提としており、未使用のまま一定時間が経過すると失効します。目安は数分程度です。トークンを受け取ったら速やかに使用し、キャッシュしたり保持したりしないでください。(出典: docs.omise.co/omise-js)
すでに使用済みのトークンを再利用しようとするとどうなりますか?
APIはused_tokenエラーを返し、メッセージにはtoken was already used.
と表示されます。トークンは一回限りの使用のみが可能であり、chargeの作成やカードの追加に一度使用されたトークンは、そのchargeが成功したかどうかにかかわらず、再び使用することはできません。(出典: docs.omise.co/api-errors)
他のAPIにあるような、特定のドメインに公開鍵を制限する機能はありますか? いいえ。Omiseはドメイン単位での鍵制限機能を提供していません。公開鍵をクライアントサイドで使用しても安全である理由は、その用途が限定されている点にあります。公開鍵ではトークンとsourceの作成・参照のみが可能であり、秘密鍵が必要な操作を行うことはできません。(出典: docs.omise.co/api-authentication)
作成できるトークンの数にレート制限はありますか? はい。トークン作成を処理するOmiseのVault(トークン化専用のエンドポイント)は、メインのAPIよりも大幅に低いレート制限が設定されています。具体的な数値は公開されていません。短時間に多数のリクエストを送信する場合は、並列で一斉に送るのではなく間隔を空けて送信し、セール開催など高トラフィックが見込まれるイベントの前にはsupport@omise.coまでご連絡ください。(出典: docs.omise.co/api-rate-limiting)
トークンを使ってchargeを作成した後、3D Secureは別途対応する必要がありますか?
場合によります。アカウントで3D Secureが有効になっている場合、charge作成のレスポンスにauthorize_uriが含まれることがあり、charge完了前にカード保有者をこのURLへリダイレクトして銀行側での認証を行う必要があります。3D Secureは、旅行、デジタル商品、ゲームなど、不正利用やチャージバックが発生しやすい特定の業種では必須となり、これはOmiseの不正対策アナリストが判断します。それ以外の加盟店にとっては任意ですが、高額または高リスクな取引には導入が推奨されます。2022年10月時点では3D Secure 2(3DS2)のみに対応しており、3DS1は廃止されているため、authorize_uriへのリダイレクトと、それに伴うフリクションレス・チャレンジフローの両方を想定しておく必要があります。(出典: docs.omise.co/3d-secure)