モバイルアプリケーションに支払いの受け入れを埋め込むか、PCI DSSとPA DSSを忘れられる理由

PCI DSSは必要ですか?



遅かれ早かれ、オンライン支払いをオンラインで受け入れるオンラインストアとモバイルアプリケーションの所有者と開発者の大多数は、「私のプロジェクトはPCI DSS規格に準拠するべきですか?」



PCI DSSは、支払いカードの処理分野のすべての組織(小売店、処理センター、金融機関、サービスプロバイダー、およびカード会員データや重要な認証データを保存、処理、または送信するその他の組織)に適用されるセキュリティ標準です。 。


PA-DSS標準は、カード会員データや重要な認証データを保存、処理、または送信するアプリケーションプロバイダーおよびその他のアプリケーション開発者に適用されます。





画像



ウェブサイトのすべては非常にシンプルです。統合中に、認定支払いゲートウェイのPCI DSSウェブサイトにあるカードデータ入力フォームに支払人をリダイレクトするか、認定ウェブサイトからもフレーム内にこのページをダウンロードする技術ソリューションを使用するだけで十分です。 この場合、カードデータはサーバーを介して保存または送信されず、販売者のウェブサイトはウェブブラウザのセキュリティポリシーにより支払いゲートウェイフレームにアクセスできないため、販売者はセキュリティ標準の範囲に含まれません。



モバイルアプリケーションでは、事態はもう少し複雑です。 モバイルアプリケーションがカードデータを要求した場合、自動的にPCI DSS規格に該当するという誤解がよくあります。 しかし、実際には、PCI DSSの標準を開発している組織(PCI SSC-Payment Card Industry Security Standards Council)は、モバイルアプリケーション用の個別の標準をまだ発行していません。 そして、これは標準がまだ拘束力がないことを意味しますが、モバイルアプリケーションの最も人気のあるカテゴリー、 すなわち



カテゴリ3.あらゆる家庭用ハンドヘルドデバイス(スマートフォン、タブレット、PDAなど)で実行される支払いアプリケーション。その機能は支払いの採用に限定されません。





ただし、モバイルアプリケーションは、バックエンド(課金およびメインビジネスロジックを提供するサーバー側)なしでは存在できないため、支払いの処理に必要な情報を販売者のサーバーに転送します。 ここに微妙な違いがあります-モバイルアプリケーションの開発者が意図的または偶然にアプリケーションをプログラミングして、認証されていないサーバーに支払いカードデータを転送しないように、モバイル支払いSDKはカードデータを読み取れないようにする必要があります。 この制限により、PCI DSS要件が廃止されます。



PCI DSSは、カード会員データを保存、処理、送信しない場合、または顧客のカード会員データにアクセスできない場合、決済アプリケーションプロバイダーに直接適用することはできません。





Androidソリューションの例を使用して、Fondyモバイル決済サービスSDKでどのように実装されるかを見てみましょう( iOS SDKもあります )。



解決策は、SDKライブラリによって作成されたビューにカードデータを入力することです。モバイルアプリケーションは、このビューのパブリックメソッドを使用して支払いを開始し、フォームを様式化し、支払い完了に関する情報を受け取ります。



Android用のデモアプリケーションの例



まず、支払いフォームの視覚的な構造-レイアウトを作成します(ちなみに、デモアプリケーションのソースコード全体はgithubにあります )。



activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/btn_amount" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/lbl_amount" /> <EditText android:id="@+id/edit_amount" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" android:maxLength="7" android:inputType="number" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" android:text="@string/lbl_ccy" /> <Spinner android:id="@+id/spinner_ccy" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" android:text="@string/lbl_email" /> <EditText android:id="@+id/edit_email" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" android:inputType="textEmailAddress" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" android:text="@string/lbl_description" /> <EditText android:id="@+id/edit_description" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="7dp" /> <com.cloudipsp.android.CardInputView android:id="@+id/card_input" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:id="@+id/text_card_type" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:visibility="gone" /> <Button android:id="@+id/btn_pay" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:gravity="center" android:text="@string/btn_pay" /> </LinearLayout> </ScrollView> <com.cloudipsp.android.CloudipspWebView android:id="@+id/web_view" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone"/> </RelativeLayout>
      
      









アプリケーション内のカードデータを除くすべての要素が異なり、カード番号、有効期限、CVV2を入力するためのフォームがクラスcom.cloudipsp.android.CardInputViewにカプセル化されていることに注意してください。 次のようになります(テストでは、ドキュメントで指定されている詳細を使用できます: https : //www.fondy.eu/ru/info/api/v1.0/2 ):



画像



同時に、クラスcom.cloudipsp.android.CardInputViewに属する要素を含むすべての要素は、メインアプリケーションの設計に合わせて簡単にスタイル設定できます。 また、3DSecureに接続されたカードを使用してアプリケーションをさらに処理するには、クラスcom.cloudipsp.android.CloudipspWebViewの要素が必要です。これは、支払人が個人のパスワードを入力するために発行銀行のWebサイトにリダイレクトされるWebViewです(この図では、作業をエミュレートするページ) 3dsecureサーバーサーバーカード発行者:



画像



次に、アプリケーションロジックpublic class MainActivityを実装するメインクラスに移りましょう。 Cloudipspクラスオブジェクトを初期化します。



  @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.btn_amount).setOnClickListener(this); editAmount = (EditText) findViewById(R.id.edit_amount); spinnerCcy = (Spinner) findViewById(R.id.spinner_ccy); editEmail = (EditText) findViewById(R.id.edit_email); editDescription = (EditText) findViewById(R.id.edit_description); cardInput = (CardInputView) findViewById(R.id.card_input); cardInput.setHelpedNeeded(BuildConfig.DEBUG); findViewById(R.id.btn_pay).setOnClickListener(this); webView = (CloudipspWebView) findViewById(R.id.web_view); cloudipsp = new Cloudipsp(MERCHANT_ID, webView); spinnerCcy.setAdapter(new ArrayAdapter<Currency>(this, android.R.layout.simple_spinner_item, Currency.values())); }
      
      





次に、クラスcom.cloudipsp.android.Cardのオブジェクトにハンドラーをアタッチして、カード番号を入力した結果を取得します。



  @Override public void onCardInputErrorClear(CardInputView view, EditText editText) { } @Override public void onCardInputErrorCatched(CardInputView view, EditText editText, String error) { editText.getText(); }
      
      





これで、ユーザーがいつデータ入力を完了するかがわかります。エラーが発生した場合は、問題に関する情報を受け取ります。 カードデータの入力後、注文を作成できます。



  if (card != null) { final Currency currency = (Currency) spinnerCcy.getSelectedItem(); final Order order = new Order(amount, currency, "vb_" + System.currentTimeMillis(), description, email); cloudipsp.pay(card, order, new Cloudipsp.PayCallback() { @Override public void onPaidProcessed(Receipt receipt) { Toast.makeText(MainActivity.this, "Paid " + receipt.status.name() + "\nPaymentId:" + receipt.paymentId+"\n Signature:"+receipt.signature, Toast.LENGTH_LONG).show(); } @Override public void onPaidFailure(Cloudipsp.Exception e) { if (e instanceof Cloudipsp.Exception.Failure) { Cloudipsp.Exception.Failure f = (Cloudipsp.Exception.Failure) e; Toast.makeText(MainActivity.this, "Failure\nErrorCode: " + f.errorCode + "\nMessage: " + f.getMessage() + "\nRequestId: " + f.requestId, Toast.LENGTH_LONG).show(); } else if (e instanceof Cloudipsp.Exception.NetworkSecurity) { Toast.makeText(MainActivity.this, "Network security error: " + e.getMessage(), Toast.LENGTH_LONG).show(); } else if (e instanceof Cloudipsp.Exception.ServerInternalError) { Toast.makeText(MainActivity.this, "Internal server error: " + e.getMessage(), Toast.LENGTH_LONG).show(); } else if (e instanceof Cloudipsp.Exception.NetworkAccess) { Toast.makeText(MainActivity.this, "Network error", Toast.LENGTH_LONG).show(); } else { Toast.makeText(MainActivity.this, "Payment Failed", Toast.LENGTH_LONG).show(); } e.printStackTrace(); } }); }
      
      





ご覧のとおり、統合は非常に簡単であり、アプリケーション開発者の側で大きな労力を必要としません。 同時に、SDKは2つの問題を同時に解決します。マーチャントに支払いカードでの支払いを受け入れるためのツールを提供し、セキュリティ標準の認証に合格する必要をなくします。



All Articles