Skip to content
[015]2026.06.01log

開いていた扉

ローンチ前のセキュリティ点検で見つけたもの

ローンチが近づくにつれ、一つのことがずっと気にかかっていた。セキュリティだ。

会社ならセキュリティチームがある。コードを検討する同僚がいて、リリース前に侵入テストというものもする。私にはそんなものがない。コードを読めない私が、セキュリティの穴を目で見つける可能性は、ないと見るのが正直だ。

だからAIにやらせた。役割を定めてやった。「あなたはシニアセキュリティ検討者だ。決済、認証、データアクセス——全部疑って全部確認しろ。」

検討結果が返ってきた。決済検証は堅牢だ。暗号化も定石だ。認証もサーバーできちんと確認している。ここまで読みながら安心した。そして次の行で安心が終わった。

致命的な問題1件。データベース関数8個が、誰にでも開いています。

説明はこうだった。データベースには「このユーザーのノート一覧を取り出して」といった仕事をする関数がある。その関数にユーザーIDを入れると、その人のデータが出てくる。問題はこの関数を呼び出せる権限だった。本来はサーバーだけが呼び出せるべきだ。ところがデータベースは、関数を作るとデフォルトで全員に実行権限を与える。私はそのデフォルトを知らず、だから変えなかった。

結果として、ログインすらしていない人が任意のユーザーIDを入れて呼び出せば、その人のノートとトピックと電子書籍の一覧が出てくる状態だった。実際にできるか確認してみた。できた。扉は本当に開いていた。

背中から冷や汗が出た。ユーザーのデータを守ってあげると暗号化だ何だとしておいて、裏口が開いていたのだ。誰もその扉から入ってこなかったのは、まったくの運だった。まだサービスが知られていないという運。

修正自体は一日もかからなかった。関数8個の権限を回収し、サーバーだけが呼び出せるように施錠した。施錠されたことを三度確認した。

その日に知ったことが二つある。

一つ。デフォルトは設計ではない。データベースが扉を開けておくのがデフォルトなら、閉めるのは私の仕事だ。「知らなかった」という言い訳は、私の家では通じない。私が知らなければ、誰も知らないままサービスが回る。

二つ。同じ失敗はチェックリストになるべきだ。この8個の関数は数か月にわたって一つずつ作られ、全部同じ失敗を繰り返していた。最初の関数で捕まえていたら、残りの七個はなかっただろう。だから開発ルールの文書に一行を追加した。この種の関数を作るときは、必ず権限から回収すること。次に作る関数は、このチェックリストを通過して生まれる。

セキュリティは機能ではないので画面に見えない。うまくやっても何も起きないのがセキュリティだ。何も起きない状態を作るために一日を使い、その一日はこの旅で最もよく使った一日の一つだったと思う。


🔧 このエピソードの技術用語解説

IDOR(Insecure Direct Object Reference) 他人のデータを指すIDを入れ替えると、そのまま閲覧できてしまう脆弱性。「自分の注文番号1001を1002に変えたら他人の注文が見える」が典型的な例。

RPC(Remote Procedure Call) データベースやサーバーにあらかじめ作っておいた関数を外から呼び出す方式。今回の事件の舞台。

REVOKE / GRANT データベースの権限を回収し(REVOKE)、付与する(GRANT)命令。今回の修正の核心は「全員から回収し、サーバーだけに付与」だった。

侵入テスト(Penetration Test) 攻撃者の立場で実際に突破できるか試すセキュリティ点検。今回はAIがその役割を担い、実際に突破された。