はじめに
はじめまして、 DeSC ヘルスケア 製品開発統括部プロダクト開発部の田代弘平です。
私の部署では、「楽しみながら、健康に。」をコンセプトに、ヘルスケアエンターテイメントアプリ kencom を開発しています。 ウォーキングイベントを定期的に開催したり、健康づくり関連の記事が閲覧できるなどの、健康増進を促す仕組みを備えたアプリです。
2015 年のサービス開始以来、健康保険組合・健診医療機関・地方公共団体・生命保険会社など 125 団体、約 800 万人の方々にサービスを提供しており、ユーザーがアプリを月に 1 回以上起動する継続率は約 60%以上の水準を維持しています。
( kencom の取り組み: ヘルスケアエンターテインメントアプリ「kencom」を 岡山県津山市に提供し、健康増進と医療費の適正化を支援 )
この度、kencom の健診結果や医療費お知らせ機能において、マイナポータルと連携したデータを表示できるようになりました。 (※該当機能は、条件を満たした一部のユーザのみ利用可能です)
本記事では、その機能と、それらをどのように実装したかをご紹介します。
マイナポータル連携 とは
マイナポータル連携とは、マイナポータルと外部ウェブサイトをつなぐことで、マイナポータル API を経由して保険医療を受けた記録などを外部から参照できる機能です。 kencom アプリでは、マイナポータル連携により、 健診結果や医療費のお知らせ・おくすり履歴を kencom から見られるようにしています。
また、今までの健診結果などをエクスポート(ダウンロード)したり、インポート(アップロード)することもできます。 (情報を削除したい場合は、アプリから削除できるほか、kencom を退会すると自動的に情報が削除されます。)
以下では、これらの機能をどのように実現したかをご紹介します。
API によりデータを取得する
マイナポータルでは、医療情報を取得するための API がデジタル庁によって提供されており、一定の条件を満たせば、申請することで利用が可能です。
情報取得の流れは、以下の通りです。
- ユーザはアプリの連携画面からマイナポータルのページに移動し、認証を行います。
- 認証を実施した後、kencom はマイナポータルの API にアクセスし、健診結果や医療費のお知らせ・おくすり履歴 の表示に用いる情報を xml 形式で取得します。
- 取得した xml データは、Google Cloud Storage のバケットに保存するとともに、データベースにも情報を保存します。これらは個人情報ですので、暗号化して保存しています。
例えば、健診情報のデータ保存だと、データベース上で 2 種類のレコードを管理しています。 一つは xml ファイルを管理するためのもので、1 ファイルにつき 1 レコードを保存します。 もう一つは、健診 1 回分ごとに 1 レコードを保存するもので、各健診データに対して暗号化された xml データをカラムに格納しています。
なお、1 つの xml ファイルには複数回の健診データが含まれる場合があり、その場合は 1 つのファイルに複数の健診レコードが紐づく形になります。 表示時には、保存された xml を復号・パースし、必要な情報を抽出します。 必要な情報の抽出を表示時に行うことで、表示要件の変更に対しても柔軟に対応できます。
参考:マイナポータル API 仕様公開サイト
取得したデータを解析する
健診結果・医療費のお知らせ・おくすり履歴 の表示に用いる情報 は xml 形式です。 xml 内に、健診項目を表すコードなどが含まれており、表示するためには、 xml を適切にパースし、必要箇所を取り出す必要があります。 そこで、xml の形式を構造体として、コード内で厳密に定義し、パースするようにしました。
イメージとしては、以下のような xml をパースします。 この xml サンプルでは ‘体重’ を健診結果として表しており、value フィールドに計測値が格納されます。
<entry>
<metric id="WEIGHT" description="体重">
<measurement value="70.5" unit="kg" />
</metric>
</entry>
これを、以下のように構造体として定義します。
type Entry struct {
XMLName xml.Name `xml:"entry"`
Metric struct {
ID string `xml:"id,attr"`
Description string `xml:"description,attr"`
Measurement struct {
Value string `xml:"value,attr"`
Unit string `xml:"unit,attr"`
} `xml:"measurement"`
} `xml:"metric"`
}
(※実際の xml の構造とは異なります)
実際の xml ファイルは、複数の健診結果が含まれるなど非常に複雑な構造ですが、 厳密に xml の構造を定義しておくことで、誤りなくデータを表示できます。 また、異常なデータが入ってきた場合に、エラーを検知できます。
インポート機能とその実装
インポート機能は、健診結果・医療費のお知らせ・おくすり履歴 の表示に用いる xml ファイルをアップロードして、kencom から見られるようにする機能です。
xml ファイル はさまざまな健康アプリ間で共通の仕様となっており、他社のアプリから、kencom へのデータの引っ越しも可能です。 インポート機能によって、ユーザはアプリを変更しても、健康情報を引き続き kencom で見ることができます。
インポート機能は、間違ったデータが入ってくる可能性もあるため、とくに実装には注意した機能です。 前述した通り、xml の構造は厳密に定義されているため、間違ったデータが入ってきた場合には、エラーとして、処理を中断できます。 また、インポート時に無害化処理を施すことで、有害なデータを取り込まないようにしています。
加えて、開発チームとは独立した別のチームが、SQL インジェクションや XSS をはじめとした脆弱性の診断を行い、安全性を担保しました。 取り込まれた、xml ファイルは、マイナポータルから連携されたもの同様、暗号化の上で保存されます。
エクスポート機能とその実装
エクスポート機能は、kencom に保存されている、健診結果・医療費のお知らせ・おくすり履歴 の情報を、 xml ファイルでダウンロードできる機能です。
マイナポータルから取得した xml ファイルやインポートした xml ファイルを、ZIP 形式で圧縮した形で、ダウンロードできます。 圧縮されたファイルは Google Cloud Storage のバケットに配置され、署名付き URL が発行された上で、その URL をユーザに渡しています。 この署名付き URL は短期間のみ有効で、バケット上のファイル自体も短時間で削除されるため、不正アクセスのリスクを最小限に抑えています。
Google Cloud Storage にはファイルのライフサイクルを管理する機能がありますが、削除までの設定が日単位で、最短でも 1 日後の削除となるため、セキュリティ上十分ではありません。そこで、より短時間での削除を実現するために、独自の削除タスクを実装しました。
ファイルのエクスポートと、ファイル削除の流れは、以下の通りです。
- ユーザがエクスポートを実行
- GCS にファイルを配置
- xml ファイルを ZIP 圧縮し、GCS の バケットにアップロードします。
- このとき、アップロードしたオブジェクトのキー を保持しておきます。
- 署名付き URL を発行
- アップロードしたファイルに対して、署名付き URL を発行してユーザへ返します。ユーザはファイルのダウンロードができます。
- CloudTasks に削除タスクを登録
- ファイルを削除するためのタスクを CloudTasks に登録します。
- 削除タスクによる削除エンドポイント呼び出し → ファイル削除
- 一定時間後(署名付き URL の期限切れ後)、削除タスクにより “ファイルを削除するためのエンドポイント” へ リクエストが送信されます。
- 削除用エンドポイントのロジックが実行され、GCS 上のファイル削除が行われます。
- 事前に保持したオブジェクトのキーにより、削除対象のファイルが特定できます。
以上の流れにより、バケット上のファイルは短時間で削除することで、セキュリティを担保しています。
参考
Google Cloud Storage のライフサイクル管理
Google Cloud Storage 署名付き URL
おわりに
この記事では、kencom におけるマイナポータル連携の仕組みと実装について解説しました。 本記事を通して、マイナポータルを活用した kencom に関心を持っていただけたら幸いです。
謝辞
本記事の作成にあたり、デジタル庁の担当者様には丁寧に対応いただき、内容をご確認いただくなど大変お世話になりました。この場を借りて御礼申し上げます。
最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。