自分の作ったシステムに、わざと外から触ってみたことがある。
ログインもしていない、ただの第三者のふりをして、公開されているデータの取得口を叩く。お客様の画面が使っている、予約枠やイベントの一覧を返すところだ。返ってきたデータを眺めていて、手が止まった。そこに、出てはいけないものが混じっていた。
内部用のURLが、混じっていた
返ってきた一覧の中に、オンライン会議のURLと、アンケートフォームのURLが入っていた。
どちらも、本来は予約した人にだけ、確定の連絡で個別に伝えるものだ。誰でも取れる公開の一覧に、混ぜて返すものではない。なのに、データを組み立てるときに、内部で持っている項目を、そのまま全部返していた。
悪用しようと思えば、予約していない人でも会議URLを拾える。地味だが、立派な情報漏れだった。
つい、全部を返してしまう
なぜ混じったのか。理由は単純で、楽だったからだ。
データの一行を読んで、まるごとオブジェクトにして返す。そのほうがコードは短い。一つひとつ「これは返す、これは返さない」と選ぶより、手が少ない。だから、つい全部を渡してしまう。
でも公開のAPIは、「何を返すか」ではなく「何を返さないか」を決める場所だ。内部の都合で持っている項目と、外に見せていい項目は、別物だ。そこを分けていなかった。
公開用と、管理用を分ける
直し方は、応答を二つに分けることだった。
公開の一覧には、本当に必要な項目だけを詰める。会議URLやアンケートURLのような内部の情報は、ログインした管理者だけが取れる、別の口に移す。同じデータでも、誰が見るかで、返すものを変える。
便利な既定値ほど、危ない
「全部返す」は、いちばん楽な既定値だった。
書く手は少ないし、後から「あの項目も欲しい」と言われても困らない。けれど、楽なほうに倒すと、見せてはいけないものまで一緒に出ていく。守りでは、足すより引くほうが安全だ。
だから公開する側は、最初に出すものを白紙にして、必要なものだけを一つずつ足していく。「いらないものを消す」のではなく、「いるものだけ載せる」。同じ結果のようでいて、漏れの起きやすさが全然違う。消し忘れは漏れるが、足し忘れは漏れない。
自分のAPIを、他人の目で叩く
この件以来、機能を作ったら、最後に一度、ログインせずに自分のAPIを叩いてみるようになった。
作っている最中は、どうしても「正しく使う人」を想定してしまう。けれど外には、正しく使わない人も、ただ覗いてみる人もいる。自分のコードを、他人の——それも少し意地の悪い——目で見る。その一手間が、漏れを表に出る前に止めてくれる。
人に指摘されて直すより、自分で見つけられたほうが、ずっといい。指摘される頃には、もう誰かに見られているかもしれないのだから。