JPQRを読んでみる

# JPQRとは
[JPQRについて | 一般社団法人キャッシュレス推進協議会](https://www.paymentsjapan.or.jp/jpqr/)
JPQRとはQRコード決済に使用するQRコードの統一規格です。
PayPay、LINE Pay、メルペイなどいろいろなコード決済が存在しますが、それぞれ独自の仕様で作られているのが現状です。
それらを1つの規格に統一することによってコード決済の規格の乱立状態を解消・防止し、店舗及び消費者にとってわかりやすいコード決済手段を提供しようというだそうです。

いくつかの決済アプリではすでに対応されており実際に試すことができます。

対応店舗はまだ少ないですが、一部の地域（岩手県、長野県、和歌山県、福岡県）で実証実験が行われています。

## QRコード決済の種類
QRコード決済にはCPM（利用者提示型）とMPM（店舗提示型）大きく2つの種類があります。
普段QRコード決済を使っている人はすぐわかると思いますが、QRコード決済アプリではQRコードを表示する画面とQRコードを読み取る画面があります。

決済アプリでQRコードを表示し**店舗レジで読み取ってもらう方式**がCPM
店舗のレジに表示されているQRコードを**決済アプリで読み取る方式**がMPM
になります。

|CPM|MPM|
|---|---|
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/c8fcdfdd-c069-a8d5-a00e-208500b3206d.png" width=200>|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/5f8ad55a-1fcc-0ef4-a03b-6b9668286ae0.png" width=200>|

# QRコードを読んでみる
JPQRの仕様は公式のガイドラインが一般に公開されています。
 [コード決済に関する統一技術仕様ガイドライン【利用者提示型】CPM（Consumer-Presented Mode）](https://www.paymentsjapan.or.jp/wordpress/wp-content/uploads/2019/10/CPM_Guideline_1.2.pdf) 
 [コード決済に関する統一技術仕様ガイドライン【店舗提示型】MPM（Merchant-Presented Mode）](https://www.paymentsjapan.or.jp/wordpress/wp-content/uploads/2019/10/MPM_Guideline_1.1.pdf) 

各方式でのアプリの対応状況ですが、MPMはすでにいくつかのアプリが対応済みですが、CPMについてはまだ対応されてなさそう（？）なので今回はMPM方式を見ていきたいと思います。
[利用者のみなさま向けページ｜統一QR「JPQR」普及事業](https://jpqr-start.jp/consumer/index.html)

### MPM方式について
読み取る前にMPM方式についてもう少し詳細を。
MPM方式は更に静的コードと動的コードの2種類に分けられます。
静的コードというのは固定のコードで毎取引で同じものを使用します。
動的コードというのは決済ごとに動的に生成されるコードです。

各方式での格納データについても上記のガイドラインに載っていますが、2つに大きく違いはありません。
主な違いは、QRコードに取引金額が含まれているか含まれていないかです。
動的コードの場合はアプリで読み取った際その支払いの金額がすでに入力されて表示されると思います。

### 読み取ってみた
前述の通りMPMには2つの方式がありましたが、動的コードの方は実際に店舗のレジで発行する必要があるので今ここで例を用意することは無理ですね。
静的の方も実物がないと読み取れませんが、ネットで調べてみたところいくつか出てきました。

```
00020101021126680019jp.or.paymentsjapan0113229080201309402040000030600000104060000005204XXXX53033925802JP5909yoshitake6003XXX6107805006164130002JA0103よし竹63040B1E
```

これが実際に読み取ったものです。
ガイドラインにある格納データの表と照らし合わせて見ていきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/66c9f5c4-5793-0c6c-ee89-8475e50e0e82.png" width=500>

各データは [ID][Length][Value] の順に並んでいます。

先頭の2つのデータについて見てみますと、このようにID、Length、Valueで並んでいることがわかります。
![untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/35756c08-842c-3c5e-29ec-12c072ee976c.png)

では、上記のコードを読み解いていくとこのようになります。

|項目名|ID|Length|内容|
|---|---|---|---|
|仕様バージョン|00|02|01|
|静的/動的フラグ|01|02|11|
|契約店情報|26-51|？|6680019jp.or.paymentsjapan011322908020130940204000003060000010406000000|
|業種|52|04|XXXX|
|取引通貨|53|03|329|
|国コード|58|02|JP|
|契約店名|59|09|yoshitake|
|契約店所在地|60|03|XXX|
|契約店郵便番号|61|07|8050061|
|契約店情報|64|13|0002JA0103よし竹|
|チェックディジット|63|04|0B1E|

「静的/動的フラグ」と「契約店情報」は更に詳細に情報が載っていて、これも [ID][Length][Value] の順に並んでいます。

##### 契約店情報
|項目名|ID|Length|内容|
|---|---|---|---|
|統一店舗識別コードレベル１|01|13|2290802013094|
|統一店舗識別コードレベル２|02|04|0000|
|統一店舗識別コードレベル３|03|06|000001|
|統一店舗識別コードレベル４|04|06|000000|

統一店舗識別コードは、店舗を4つの階層で管理されていて、どの会社（1）のどのショッピングモール（2）内のどの店舗(3)のどのレジ（4）みたいな感じで表現されています。
また登録されていない各階層にはすべて0が割り振られます。
なのでこの例だと、「よし竹の〇〇店」みたいなことになりますね。

##### 契約店情報
|項目名|ID|Length|内容|
|---|---|---|---|
|使用言語|00|02|JA|
|契約店名|01|03|よし竹|


# 各決済アプリでの動き

メルペイとOrigami Payで試してみました。

##### とりあえず店舗のQRを読み取ってみる

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/7731fea9-5973-fc68-1c7a-7e4e0a945387.png">　　<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/fdeb7d8a-cca3-3e32-d9d0-29c3e899d48b.png">

当たり前ですが普通に読めます。

ではコードをちょっといじってみるとどうでしょうか？

##### 契約店名を書き換える

ここでアプリ間で差が出てきました。
Origami Payでは正常にその店舗のQRとして読み取ることができましたが、メルペイではエラーになってしまいました。
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/b5d1cc05-d225-0f10-865a-89ad176c1c39.png">


##### 統一店舗識別コードを別の店のものに書き換える
メルペイでは上のケースと同様エラーになりました。
Origami Payでは書き換えた方の店舗として認識され決済もできてしまいました。
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/aeaebe9c-6618-5cb9-b9a3-13c9685dc751.png">


##### チェックディジットを書き換える
メルペイでは上のケースと同様エラーになりました。
Origami Payでは正常にその店舗のQRとして読み取ることができました。

##### 動的コードに書き換える
ID:01の静的/動的フラグを12に書き換えID:54の取引金額に1000を入れてみました。
メルペイでは上のケースと同様エラーになりました。
Origami Payでは正常に動的コードとしてQRとして読み取ることができました。
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14751/6edad02f-4bff-9b67-189b-5187e333a0b2.png">



# 静的QRコードの管理 
ガイドラインにも書いてありますが、静的QRコードはあらかじめ店舗が印刷したQRコードを使用するため、設置されているQR コードが不正に貼り換えられることに十分注意する必要があります。
今回試してみたように仕様も公開されていますからどう書き換えたら良いかもすぐ考えつきます。
決済画面に店舗名など書いてありますので多くの人は気づくかもしれませんが、まさか偽装されてるなんて思わないので「はいはいはいー」とろくに確認もせず実行ボタンを押しちゃう人もいるでしょう。
ガイドラインに以下のように対策が書いてありますが結構アナログですよね。


> 例えば、静的 QR コードを容易に複製することが難しいパネル・特殊な用 紙等に印刷する、設置してある静的 QR コードの上に別の静的 QR コードが貼られて いないか契約店に定期的に確認するよう指導する、定期的に契約店が自分で決済を してみてその正当性を確認するよう指導する、といった手段が考えられる。

# まとめ
JPQRが広まるとユーザーとして嬉しいかと言われればたぶんそんなに嬉しいことはない気がしますが、店舗としてはいろんなQRコードをレジ前に置く必要がなくなる、各決済サービスごとの使い方を覚える必要がなくなるなどメリットはあるのかなと思います。

今回いくつかQRコードを書き換えて試してみましたが、改めてコード決済を利用するにあたっては利用する側も注意を払う必要があるなと感じました。
また、メルペイでは正常なQRしか読めないようになっていましたが、Charlesで通信をキャプチャすることもできないようになっていました（中間者攻撃対策として不正なSSL証明書をはじいている？）。
自分はセキュリティに関して詳しくないのですが、開発者としてもユーザーを守ることを意識して開発しないといけないんだなと改めて感じるきっかけになりました。