2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

IPアドレス流出はなぜ起こったのか?(推理)

Last updated at Posted at 2020-08-14

TL;DR

  • 某サービスに「ソースコードからIPアドレスが流出してしまう」という脆弱性が発見され、世間を騒がせていますね。
  • そもそもなぜソースコードからIPアドレス流出したの?という問題について語ってみます。
  • 筆者は某サービスの開発に関わっていたわけではないので、当記事で語るパターンでの流出だったとは断言できません。
  • そのため、起こりうる一つの「怖いパターン」の事例共有として、ご参考までによろしくお願いいたします。
  • 初学者にもわかるように少し噛み砕いてご説明します。

前提

まず大前提ですが、統計のためやバグの追跡のためにサービス利用者のIPアドレスを収集すること自体は不思議なことではありません。
問題は、__なぜそれがフロントから見える状態になっていたのか__です。

統計を取るにせよ、サービスに嫌がらせをしていた投稿者を特定してそのIPアドレスをブロックするにせよ、DBに値が残っていれば十分で、それをフロントに持ってくる意味ってありませんよね?
少なくとも私はパッと思いつきません。
それにフロントに持ってくるということは、今回のような「流出のリスク」があるということでもあります。

要は、__「DBにさえあれば良いはずのIPアドレスがなぜフロントから見えてしまったのか?」__が今回理解すべきことになります。

サーバサイドの動きを考えてみる

その前提の上でDBに思いを馳せてみましょう。

例えば__「ブログ投稿サービスで、記事の情報を保存する『Article』テーブルが存在していた」__と考えてみます。
正規化がどうのこうのという難しいことは考えなくて良いです。
以下の要件で考えてみましょう。

  • Articleテーブルは1記事の情報を1レコードで保存している
  • Articleテーブルには「記事タイトル」「本文」「投稿日付」などのカラムがある
  • そのカラムの中に「IPアドレス」もあった

不思議な仮定ではないはずです。

さて、お話が変わって現在三大フルスタックWebフレームワークといえば

  • Rails
  • Laravel
  • Django

です。本題ではないのでなぜこれが三大なのかという議論は避けますが、少なくともよく使われているフレームワークであることには間違いないでしょう。
参考:どれ使うべき?3大WebフレームワークRails・Django・Laravelを徹底比較してみた

その中で、RailsとLaravelのORM(DBへのアクセスを簡単にしてくれる仕組みのことですね) には共通の特徴があります。

Active Record__という特徴です。
ざっくりといえば、
「DBの1レコードをひとつのオブジェクトとして扱おう!」__という考え方です。
賛否両論、メリットデメリットがある仕組みではあるのですが、個人的には大好きな仕組みです。
詳しくはこちらもどうぞ (宣伝)
開発への異常な愛情 または私は如何にして嫉妬を止めてActive Recordを愛するようになったか

閑話休題。

さて、例えばLaravelの場合、その"Active Record"を利用すると、このようなことができます。

TestController.php
// ログインしているユーザーの最新の記事のIDを特定
$currentArticleId = $this->getCurrentArticleIdByLoginUser();
// 最新の記事(1レコード ≒ 1オブジェクト)を取得
$currentArticle = Article::find($currentArticleId);
// オブジェクトをビューに渡す
return view('current_article.index',compact('currentArticle'));

分かる人は「コントローラーでそんな処理するな」とか「なんでコントローラーで明らかに特定のModel専用の独自処理を実装してるの?怖……」とか言いたくなったかもしれませんが、とりあえず今は無視してください。

要するに、__「Articleテーブルの、ログインユーザーによる最新の1レコード ≒ 1オブジェクト」を取得して、フロントにパスしている__ということだけ伝われば十分です。compact('currentArticle') はそのためのおまじないです。

さて、このオブジェクトが格納されている変数$currentArticle は、当たり前ですが1レコードの情報全てが格納されています。
フロント側……Laravelは.blade.phpというファイルにHTMLとPHPが融合したようなものを記載していくのですが……このbladeファイルの中では、$currentArticle が持っている情報全てにアクセスすることができます。

index.blade.php
<h1>{{ $currentArticle->title }}</h1>

こう書くだけでWebページにタイトルが表示されます。とても便利です。

話を戻しましょう。なぜフロントでIPアドレスが見えてしまったのでしょうか?

仮説1。
bladeファイル(あるいは他のフレームワークにおける同様の機能)の中で

index.blade.php
{{ $currentArticle->ipaddress }}

と書いてしまったのでしょうか?
その可能性は低いと思われます。意味がありませんし、レビュー文化があればすぐ気付くでしょう。

仮説2。

index.blade.php
{{ $currentArticle }}

と書いてしまった?これもあまり意味がなく、すぐ気付くため考えにくいです。
ちなみに実際にこれをやってみると確かに流出はするのですが、そもそもフロントに$currentArticle の中身を展開した文字列がズラーッと表示されますw ソースコード上の流出どころの騒ぎではありませんね。

仮説3。

index.blade.php
<h1>{{ $currentArticle->title }}</h1>

と書くだけでもフロントに$currentArticle の情報は引き渡っているから、$currentArticleのメンバ変数は全て可視化されてしまっていた。
こう考えた人、ほぼ正解!
ただ少なくともLaravelくんはとても賢いので、そのようなことにはなりません。

仮説4。
フロント専用のフレームワークを使っていたことが原因。
このパターンについてご説明いたします。

JSフレームワークを使っていたとしたら?

フロントの三大フレームワーク、これは議論を待たずに

  • React
  • Vue
  • Angular

ですね。これらはいわゆる「三大フロントフレームワーク」と呼ばれるものですが、言い換えると「三大JavaScriptフレームワークです」
JavaScriptのフレームワークなんです。

さて、JavaScriptがPHPのオブジェクトを使う方法はあるでしょうか?
PHPでなくても、RubyでもPythonでも同じです。
使えるように変換する必要がありますよね?

そう、JSON(JavaScript Object Notation) です。
……厳密に言えば、JavaScriptのオブジェクトに変換するために、一度JSONに変換する必要があるというお話です。他にも色々方法はありますが、一番良く使われるのがJSONでしょう。

そういうわけで、

TestController.php
$currentArticle = Article::find($currentArticleId);
$currentArticleJson = $currentArticle->toJson();

のようにしてあげるとJSON(文字列)に変換できます。

あとはこのJSON文字列$currentArticleJson をフロントにそのまま引き渡せば、JavaScriptがその文字列を処理する際に流出してしまう……というオチです。

ちなみにLaravelではJSONに変換する際に「この項目はJSONに変換した際に変換の対象にしない!」と指定するためのフィールドがあります。

モデルから変換する配列やJSONに、パスワードのような属性を含めたくない場合があります。それにはモデルの$hiddenプロパティに定義を追加してください

本題ではないので詳細は省きますが、この記載から属性:"ipaddress"の指定が漏れてしまうということは十分にあり得ることです。

結論

繰り返しますが、この記事で書いたのはあくまでもあり得るパターンの一つであり、今回世間を騒がせた件は別の理由である可能性もあります。例えばそれこそ5chではIPアドレスをフロントで表示する機能もあるので、そのような機能がどこかにあったのかもしれません。

ただ、ここで書いた事例は他のIT企業でも十分に「起こりうる」ことです。
ここで紹介したパターンでは、そのリスクはフレームワークを他のフレームワークに適合させるために = 汎化させるために、「JSONへの明示的な変換」をしたことで発生するものでした。
「こうするとリスクは防げる」という銀の弾丸ははなかなかないものなのですが、少なくともJSONへの変換 = いわゆるシリアライズした上でのデータの受け渡しはときにリスクを伴う、ということは覚えておいても良いかもしれません。

お読み頂きありがとうございました。
ではまたどこかで。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?