連載「YOKOSO PAY の舞台裏」第 3 回
YOKOSO PAY のセキュリティと運用守る・気づく・直す
この記事のまとめ
- お店とお客様のお金と情報を、何重にも守っています。 カード番号は当社を通らず、データは立場ごとの権限で分け、鍵は 1 か所にだけ置いています
- 異常には、すぐ気づける仕組みにしています。 人が本番のシステムに直接触れたとき、定期処理が失敗したとき、決済の記録が合わないときは、運営にすぐ知らせが届きます
- 気づいたら、決まった流れで直します。 AI が原因と影響を調べ、直したものは品質ゲートを通って、いつもと同じ流れで本番に出ます
はじめに
合同会社Techno Vision AO は、町おこしのプラットフォーム「YOKOSO PAY」を作り、運営しています。第 1 回ではシステムの構成を、第 2 回では開発体制を紹介しました。
第 3 回は、セキュリティと運用です。お店の決済とお客様の情報を預かるサービスとして、何をどう守り、異常にどう気づき、どう直しているかを紹介します。
前半は、お店・お客様・自治体の方に向けて、専門用語を使わずに書きます。後半は、IT 事業者・エンジニアの方に向けて、使っている仕組みまで具体的に書きます。
この記事の「本番」は、お客様とお店が実際に使っているシステムと、そのデータのことです。動きを確かめるための環境 (確認用の環境) とは分けています。
お店・お客様の方へ: 何を、どう守っているか
| 心配なこと | YOKOSO PAY では |
|---|---|
| カード番号が盗まれないか | カード番号は、当社のシステムを通りません。決済の会社 (Stripe) が預かり、当社は持ちません |
| 知らないうちに請求されないか | 1 回の金額や回数に上限をかけ、カードの本人確認 (3D セキュア) を求めます。同じ支払いは 1 回だけ記録します |
| 売上や情報を、ほかの人に見られないか | ログインした人の立場ごとに、見られる範囲を決めています。お店のスタッフでも、返金や売上の操作ができるのはオーナーと店長だけです |
| アカウントを乗っ取られないか | 2 段階認証やパスキーを使えます。運営のアカウントは、2 段階認証を必ず使います |
| データが消えないか | 本番のデータは削除から守り、過去の時点に戻せるようにしています |
| 退会したら情報はどうなるか | 決めた期間がたったら、自動で消したり、誰のものか分からない形にしたりします |
| 何か起きたら | 運営にすぐ知らせが届き、決まった流れで直します |
全体像
YOKOSO PAY の守りは、「守る」「気づく」「直す」の 3 つの柱で組み立てています。これは、セキュリティの標準の考え方 (NIST のサイバーセキュリティフレームワーク) の「防御」「検知」「対応・復旧」にあたります。
| 柱 | 標準の考え方 | 主な仕組み |
|---|---|---|
| 守る | 防御 (多層防御・最小権限) | カード番号を持たない・立場ごとの権限・秘密は 1 か所・セキュリティのヘッダ・部品の版の固定・本番に出すときの承認 |
| 気づく | 検知 (監視・監査ログ) | 人が本番のシステムに直接触れたら通知・定期処理の失敗・毎朝の決済の照合・毎晩の設定の検査・画面のエラー・緊急の脆弱性 |
| 直す | 対応・復旧 | AI が原因と影響を調べる・品質ゲートを通して直す・前の版に戻す・手順書 |
守る: 何重にも守る (多層防御)
ねらい1 つの守りが破られても、次の層で止まるようにする (多層防御)。権限は、その仕事に要る最小にとどめる (最小権限)。入口 → ログイン → 権限 → データと決済の順に、層を重ねる。
1. 入口
- HTTPS通信はすべて暗号化しています。証明書は Google が管理し、自動で更新されます
- セキュリティのヘッダすべての画面に、HSTS (HTTPS を強制)・CSP (読み込んでよい先の制限)・クリックジャッキング対策 (よそのサイトへの埋め込みを禁止)・nosniff・Referrer-Policy を付けています
- API の説明書は公開しない開発のための API の説明書や、開発用の起動のしかたは、本番では使いません
2. ログイン
- ログインの基盤Firebase Authentication (Identity Platform) を使い、パスワードは当社では持ちません。API は、要求のたびにログインの証明 (ID トークン) を確かめます
- 立場ごとの入口お客様・お店のオーナー・お店のスタッフ・運営で、ログインのしかたを分けています。運営は、許可した人だけが入れます
- 2 段階認証とパスキーお客様とお店は、2 段階認証やパスキーを使えます。パスキーを登録すると、新しい端末が加わったことをメールで知らせます
- 運営のアカウント2 段階認証を必ず使い、取り消したログインの証明は受け付けません
3. 権限
- API で必ず認可する本人か、その店の人か、どの役割かを、API が要求ごとに確かめます。お店の役割はオーナー・店長・スタッフの 3 つで、お金が動く操作はオーナーと店長だけです
- データの読み書きのルール画面からデータベースへの書き込みは、すべて断ります。書き込みは必ず API を通ります。画面から直接読めるのは、ログインした本人が自分の注文の状況を見るときなど、本人に関わるものだけです。ルールはテストで確かめ、本番に出すたびに自動で反映し、毎晩ずれていないかを検査します
- 回数の制限ログインやお問い合わせなど、狙われやすい入口には回数の制限をかけています。数えるときは、偽れない送信元で数えます
- 専用の権限API や定期処理ごとに、専用のサービスアカウントで動かします。データベースも、環境ごとに届く範囲を絞っています
4. データと決済
- カード番号を持たないカードの情報は Stripe が預かり、当社のシステムを通りません
- 決済の守りStripe からの知らせ (webhook) は署名で本物か確かめ、同じ支払いは 1 回だけ記録します。注文の金額は、画面からの値ではなく、サーバがメニューから決めます。1 回の金額や回数の上限は、決済の前に確かめて断ります。アプリでのカード払いには、本人確認 (3D セキュア) を求めます
- 秘密は 1 か所にAPI の鍵などは Secret Manager だけに置きます。デプロイは鍵ファイルを使わず、短い期限の資格情報 (Workload Identity 連携) で入ります
- データの保全本番のデータベースは、削除から守り、過去の時点を指定して戻せます (ポイントインタイムリカバリ)
- 個人情報退会したお客様やお店の情報は、決めた期間がたったら、定期処理が自動で消したり、誰のものか分からない形にしたりします
5. 部品と変更の管理 (サプライチェーン)
- 部品の版の固定使っている部品 (ライブラリ・コンテナのイメージ) は、ハッシュや digest まで固定し、知らないうちに中身が変わらないようにしています
- 更新の取り込み定期の更新は、公開から 7 日たった版だけを取ります (乗っ取られた版は、たいてい数日で取り下げられるため)。セキュリティの修正は、待たずにすぐ取り込みます
- CI の部品も固定GitHub Actions で使う部品も、版の名前ではなく、中身を指す値 (SHA) で固定しています
- 秘密の混入を止める鍵やパスワードがコードに入らないよう、コミットの前の検査と、GitHub の秘密の検出・push の保護の 2 か所で止めます
- 本番に出すときの承認本番に出すときは人が承認し、main への取り込みはレビューを必須にしています
- 店頭のレシートプリンタお店の PC からの印刷は、組にしたお店の画面からだけ受け付けます。プリンタの橋渡しのソフトにも、更新が届く作りにしています
効果どこか 1 か所に誤りや漏れがあっても、それだけで全部が開くことはありません。決済の情報は、そもそも当社に置かないので、漏れようがありません。
気づく: 異常を、すぐ運営に届ける (検知)
ねらい守りは、いつか破られる前提で考える。破られたとき・壊れたときに、すぐ気づけることが、被害を小さくする。気づく仕組みが止まったことにも、気づけるようにする。
仕組み
- 人が本番のシステムに直接触れたら、すぐ通知ふだん本番の鍵やデータベースに触れるのは、決められたプログラム (サービスアカウント) だけです。人が直接触れるのは、緊急の作業か、アカウントを乗っ取られたときのどちらかです。そこで、人が本番の鍵を読んだとき、本番のデータベースに書き込んだときは、操作の記録 (監査ログ) から運営にすぐ知らせます。緊急の作業なら本人がそのとおりと分かり、身に覚えがなければすぐ乗っ取りを疑えます
- 定期処理の失敗決済の照合や期限切れの処理などの定期処理が失敗したら、すぐ知らせます
- 毎朝の決済の照合前の日の Stripe の記録と当社の記録を突き合わせます。記録の無い支払い・支払いの無い記録・金額の食い違い・返金の未反映・返金の失敗・チャージバックの未反映などが 1 件でもあれば、知らせます
- 毎晩、設定が書いたとおりかを検査サーバや権限などの設定は、すべてコード (Terraform) に書いてあります。実際の設定が、書いたとおりになっているか (画面から手で変えられていないか) を毎晩確かめます。対象は、インフラの設定・鍵の参照・データのルールと索引・ログインを許すドメインです。異常が無くても毎晩「異常なし」を 1 行出すので、検査そのものが止まったことにも気づけます
- 画面のエラー本番の画面で起きたエラーと、画面から見たサーバの失敗を、Sentry で集めます。送る前に、個人情報や秘密に見える文字は消します
- 緊急の脆弱性本番と main で動いているイメージと部品を 6 時間ごとに検査し、緊急・重要なものだけを知らせます。対応が終わるまで、毎日知らせ続けます
- 使いすぎサービス全体と AI の利用料が月の予算を超えそうになったら知らせます (下の「費用を守る」)
知らせは、Cloud Monitoring からログ・Pub/Sub・Cloud Functions を通って、運営の Slack に届きます。本番と確認用の環境で、届く部屋を分けています
効果人が本番のシステムに直接触れたこと、処理が止まったこと、お金の記録が合わないことに、その日のうちに気づけます。通知が来ないことが「何も起きていない」の証拠になるよう、検査そのものの生存も知らせます。
直す: 決まった流れで直す (対応・復旧)
ねらい気づいたら、迷わず同じ手順で直す。急いでいるときほど、いつもの品質ゲートを外さない。
仕組み
- AI が原因と影響を調べる決まった調べ方は、Claude Code のスキル (調べ方の手順を部品にして、AI が毎回同じやり方で動けるようにしたもの) にしています。アラートが届いたら、その 1 行を渡すだけで、AI が本物のログを引いて「何が起きたか・影響・原因・今すぐすること」を出します (
/alert)。脆弱性の知らせが届いたら、YOKOSO PAY のどこに当たるか・放っておくと何が起きうるか・直すべきかを出します (/vuln)。どちらも、直す作業には勝手に入りません。直すかどうかは人が決めます - 直したら、いつもの流れで出す直した変更も、コミットの前・PR・本番の前の 3 つの品質ゲートを通ります (第 2 回)。本番に出すのは、リリースする版で結合テストの全件が通っているときだけです
- 前の版に戻す出した版に問題があれば、API と画面を前の版に戻し、動いていることを確かめる手順があります
- 手順書障害のときの 1 枚の手順、鍵の入れ替え、緊急のときの操作などを、手順書にまとめています
効果調べ方が人によって変わらず、夜中でも同じ質で原因にたどり着けます。直したものが、別のところを壊して戻ってくることもありません。
実話: 定期処理の失敗に、1 か月気づけなかった
以前、本番の予約の自動キャンセルの定期処理が、設定の誤りで 1 時間ごとに失敗し続けていました。失敗は 802 回、成功は 0 回。ログには出ていましたが、運営に知らせる道が無く、1 か月近く誰も気づけませんでした。
解決設定を直しただけで終わらせず、気づく仕組みを足しました。定期処理の失敗をアラートにし、Slack へ知らせる道を作り、届いたアラートから AI が原因を調べるスキルを作りました。あわせて、定期処理ごとの権限も、届くデータベースを絞り直しました。一度の失敗を、仕組みの穴として埋めるようにしています。
費用を守る: 使いすぎで赤字にしない
ねらいお店に安く使っていただくには、思わぬ使いすぎで費用がふくらまないことが前提になる。ボットや誤り、一部の使いすぎで、サービス全体が赤字にならないようにする。
仕組み
- 月の予算と通知データベースやサーバなどサービス全体の利用料と、AI の利用料に、月の予算をかけています。超えそうになったら運営に知らせます
- 台数の上限サーバの台数に上限をかけ、思わぬアクセスや誤りで、費用がふくらみ続けないようにしています
- 今は当社が持っています今は実証実験の期間中なので、利用料は当社が持っています。枠を超えた分も含めて、お店にご負担をおかけすることはありません。下の自動延長と請求の天井は、本格的にご利用いただくときの仕組みです
- お店ごとの利用枠お店ごとに、追加の料金なしで使える月の利用枠を用意しています。目安は、お客様が店のページを月に約 15 万回 (1 日に約 5,000 回) 開くまでで、ふつうのお店の使い方なら、この中に収まります
- 止めずに続ける枠に近づいたら (80%)、お店にメールで知らせます。お店が「自動延長」を ON にしておけば、枠を使い切っても 1,000 円分ずつ自動で買い足して、止まらずに続きます。そのたびにメールで知らせます
- 請求の天井お店が決めた上限を超えて買い足すことは、ありません。攻撃や誤りで使う量が増えても、お店への請求は上限で止まります
- 運営の画面どのお店がどれだけ使っているかを、運営の画面で見ています
効果ほとんどのお店は追加の料金なしで使え、使う量が増えたお店も止まらずに続けられます。使いすぎが起きても、費用はお店にも当社にも決めた範囲に収まります。小さく安く続けられる理由の 1 つです。
これから: 利用が増えるのに合わせて、次のように広げます。
- 同じ料金で使える量を増やす配信の圧縮やキャッシュを足して、ページ 1 回あたりにかかる読み取りを減らします。同じ料金のまま、使える量が増えていきます
- ボットによる無駄な消費を防ぐ人ではないアクセスで枠や費用が減らないよう、入口で止めます (下の「これから足すもの」の WAF・ボット対策)
- 売上に合わせて構成を変えるお店とお客様の増え方と売上を見ながら、赤字にならない範囲で、適切な構成に変えていきます (第 1 回の「これからの構成」)
あえて採らなかった判断
お客様のパスキー・2 段階認証を、必須にしない
YOKOSO PAY のお客様には、旅行の途中で使う方が多くいます。毎回のログインに手間をかけると、その場で使えなくなります。とくに海外から来た方は、端末を替えたときに戻る手段 (SMS など) が限られます。そこで、お客様のパスキーと 2 段階認証は、望む方だけが使う任意のものにしています。代わりに、決済に上限と本人確認 (3D セキュア) をかけ、パスキーを登録したときは新しい端末の知らせをメールで送ります。運営のアカウントは、2 段階認証を必須にしています
端末の信頼の確認を、本番では使わない
ログインした端末を「信頼できる端末」として覚え、知らない端末からの操作を止める仕組みは作ってありますが、本番では使っていません。iPhone の Safari は、しばらく使わないサイトの保存データを消すことがあり、正しいお客様やお店が締め出されてしまうためです。確認用の環境で動かし続け、使える形になったら本番に出します。
これから足すもの
第 1 回の「これからの構成」と同じく、利用が増えるのに合わせて、次のものを足します。
- WAF・ボット対策ロードバランサの前に Cloud Armor を置き、攻撃のパターンやボットを入口で止めます。入口をロードバランサにまとめる構成の変更と一緒に行います
- 第三者による脆弱性診断自分たちの目だけでなく、外の専門家の目で確かめます
まとめ
- カード番号を持たず、入口・ログイン・権限・データと決済の層を重ね、部品と変更も管理して、何重にも守っています
- 人が本番のシステムに直接触れたとき、処理が失敗したとき、お金の記録が合わないときは、すぐ運営に届きます。検査が止まったことにも気づけます
- 気づいたら、AI が原因と影響を調べ、いつもの品質ゲートを通して直します
次回は、システムの外の話です。イベントや地域の取り組みを、企画の段階から一緒に進める伴走を紹介します。
ご意見・ご相談
セキュリティや運用へのご意見、「うちのサービスも見てほしい」といったご相談をお待ちしています。
旅行者・お店・町をつなぐ観光アプリ
YOKOSO PAY のご紹介を見る