いさやま のすべての投稿

90年生まれ。福岡在住でちょっとだけアウトローなアプリ開発者。中華が好き。

WebPageTestのプライベートインスタンスを中国国内(金盾の中)に作成する話

WebPageTestというWebサービスがあります。Webページの表示速度等を詳細に計測してくれる便利なサービスです。Akamaiの日本語ブログなどでも紹介されていました。

このサービスには計測インスタンスのロケーションが複数準備されており、世界中から自分のサイトの表示速度を計測し、結果でガッツポーズをとったり、阿鼻叫喚することができます。また、Webサービスのプログラム自体もGitHubで公開されており、プライベートなインスタンスを立てて、秘密のサイトを自分だけでひっそり計測することができます。

 

さて、世界中に設置されているWebPageTestの計測インスタンスのロケーションですが、中国国内の金盾内部には設置されていません。(香港にはあります。)調べてみると2015年ごろにはBeijing(China Unicom系回線?)にあったようですが、現在では消えているようなので、なんらかの事情で閉鎖したようです。

中国国内での表示速度は金盾や中国の回線事情などの影響で他国とは大きく違うことが予想されますので、なんとかして計測したいところなので、今回WebPageTestの計測用のプライベートインスタンスを中国国内に設置し、計測を試みることにしました。

WebPageTestは、Webアプリと計測用のエージェントから構成されており、今回は計測用のエージェントのみ中国に設置し、Webアプリは日本に置きました。同じサーバーにまとめてもよいと思いますが、中国のクラウドだと80/443などにはドメイン名をつけて公開できないので、プロキシーをなど立ててアクセスすることになります。

準備するもの

Dockerイメージの準備

計測用エージェントは推奨されているwptagentをDockerで使います。手順はドキュメントに書いています。

中国国外の回線であれば、基本的にはdocker buildするだけで動いてしまう(すごい)のですが、中国国内からはDockerfileに書かれているChromeのリポジトリーURL(http://dl.google.com/linux/chrome/deb/)にはアクセスできないため、中国国内のECSインスタンスではdocker buildだけでは動かないようです。

そこで、日本国内の環境でdocker buildして、docker saveして書き出したイメージを中国に送って動かしてみることにします(多分現地でChromium落としてwptagentの設定変えたほうがメンテしやすいけど、後のことはあまり考えていないので場当たり的に対処します。)

#ローカル環境など、日本国内の環境にて
$ git clone https://github.com/WPO-Foundation/wptagent.git
$ cd wptagent
$ docker build --tag wptagent .
$ docker save wptagent > wptagent.tar

このgit cloneしたディレクトリーそのものを中国に送ります。(方法はなんでもよい)

 

必要なプログラムの準備

ECSインスタンスにsshログインし、aptで次のパッケージをインストールする

  • docker (docker.io)
$ apt update
$ apt install docker.io

先ほどのgit cloneしたディレクトリーを持ってきて、以下のようにimageをloadします。

$ cd wptagent
$ docker load < wptagent.tar

ガガガッっとイメージが読み込まれて完成します。

後は、ドキュメントにしたがって立ち上げます。

modprobe ifb numifbs=1
docker run -d \
  -e SERVER_URL="http://my-wpt-server.org/work/" \
  -e LOCATION="docker-location" \
  -e NAME="Docker Test" \
  --cap-add=NET_ADMIN \
  wptagent

モチベーションが切れたので以上です。

Composerを活用した脆弱性ハンドリングについて

PHPカンファレンス福岡2016にて、「Composerを活用した脆弱性ハンドリング」というタイトルでLTを行いました。

スライドと制作物のご紹介、今後の展開などについて個人的な覚書として書きます。

TL;DR

  • Composer(というかPackagist)に掲載のパッケージが、脆弱性を持っているかどうかの情報を返すAPIを作りました。
  • そのAPIにアクセスする、専用のComposerプラグインを作りました。(tisayama/composer-vuln-handler)
  • Packagistのパッケージ情報と脆弱性情報のアグリゲーションには大いに問題があり、自動判別などがまったくうまくいってないので、うまく紐付いていない情報などがあれば教えてください。

スライド

内容

用語

CVE®(Common Vulnerabilities and Exposures)…「共通脆弱性指定子」米国の非営利団体MITRE社が採番している、脆弱性の識別番号

NVD(National Vulnerability Database)…米国の国立標準技術研究所が運営している脆弱性情報データベース

CPE(Common Platform Enumeration)…「共通プラットフォーム一覧」情報資産を構成する要素の名称を正規化するルール。米国の非営利団体MITRE社が策定に関与。

背景

会社で、使用しているPHPフレームワークのバージョンなどは管理しているものの、何がどう危ないと言った話がRSSフィードの目grepからしか得られていないという事情があり、もっとお手軽に脆弱性情報を得る方法を模索していました。

作りたかったもの

脆弱性情報を簡単に得られる仕組み、特に、影響するパッケージを導入しようとすると画面表示で教えてくれるような親切な仕組みがあると嬉しいのではないかと考えました。

これをPHPに落とし込むと、Composerでインストールしようとすると画面表示で教えてくれるのが理想かと思います。

先行事例

Symfonyのスポンサーで、かの有名なSensioLabsさんがSecurity Advisories Checkerというものを運営しておりました。これはcomposer.lockファイルをアップロードするなどすれば脆弱性のあるバージョンのパッケージを使用していないか検査してくれるツール及びサービスです。

書いてある説明書きを読み込むとわかるのですが、これはGitHubのContributeを通して人間が登録したアドバイザリ情報を提供するものになります。つまり人間が登録しようと思わなかった脆弱性情報は登録されません。

例えば、現時点ではCakePHPの今年の脆弱性(CVE-2015-8379)が登録されていなかったり、EC-CUBEの項目自体がなかったりします。

一方で人間が介在する強みもあり、CVEが立っていない、つまり脆弱性データベースに登録されていないものも手作業で登録されています。例えば昨年夏の、CakePHPの認証がかかったprefix routing配下に直接アクセスを許してしまう脆弱性はきちんと登録されています。

いずれにせよ、NVDに登録済みのCVEを取りこぼしているのはあまり良い話ではないので、ある程度は自動化したソリューションが必要ではないかと思います。

今回の製作物

今回、ローカルのComposerリポジトリの情報をもとに、APIに脆弱性情報がないか問い合わせるComposerプラグインおよび、APIエンドポイントとComposerとNVDのアグリゲーションプログラムを開発しました。

ComposerとNVDのアグリゲーション手法

ComposerのリポジトリのPackagistでは、パッケージの名称の形式が決められており、例えばCakePHPだったら”cakephp/cakephp” 、Symfonyだったら”symfony/symfony”などとパッケージ名称の正規化ルールがあります。

いっぽう、NVDでも同様に、影響するソフトウェアなどの名称、バージョンの正規化表記ルールがあります。それがCPE(Common Platform Enumeration)です。たとえば、CakePHPであれば、以下のように表されます。

cpe:/a:cakephp:cakephp:2.0.4

先頭のcpe:/に続く、aがソフトウェアの種別、次の:に囲まれた部分がベンダー名、次がソフトウェア名、最後がバージョンです。場合によっては後ろにアップデート名などが続きます。(CPE 2.2の場合)

表記ゆれなどの問題

ここまでの話ですと、先ほどのComposerでのパッケージ情報の表記方法からこのCPEへの変換は容易に思えます。しかし、話はそんなに簡単ではありません。実はCakePHPにはもう一つのCPEがあります。

cpe:/a:cakefoundation:cakephp:2.2.3

ベンダー名がcakefoundationになりました。また、Symfonyは以下のようになります。

cpe:/a:sensiolabs:symfony:2.3.12

Composerでの表記と違って、ベンダー部分がsensiolabsになっています。これらの表記ゆれ、情報不足などによりComposerでの表記とCPEとの間での相互変換はなかなか厳しいのです。

マッチング手法のひとまずの解

開発当初、CPE表記一覧であるCPE Dictionaryからの類推により、容易にComposer表記との間で一対一の相互変換が可能になると仮定し、CPE DictionaryをSELECTしまくるプログラムを書いていたので、上記の問題ですぐに行き詰まりました。

方法を変え、Composer側が持っているhomepageやリポジトリのURLと、CPE Dictionaryのアイテムの参考URLを突き合わせて集計を行う試みをやってみました。しかし、少なくともhomepageに関してはまともに入力されていないことが判明し、頓挫しました。(ある程度は頑張れるのですが、ゴミデータが多すぎます)

準備時間は限られていたので、最終的にどうしようもなくなり。ComposerとCPEとの結び付けについてはある程度自動で行うことに決めました。

今回は時間がなく妥協しましたが、今後はComposerバージョンに対して、生成ルールに従って自動で生成したCPEを紐付けて利用したいとも考えています。

脆弱性情報の入手

脆弱性情報はNVDのこのページから、圧縮されたXMLの形式で入手しています。展開した上でMySQLに取り込み、ごりごり処理しています。

Composerプラグイン

脇道にそれた話になりますが、今回製作した、APIクライアント側はComposerプラグインとして動作します。Composerプラグインについてはあまりまとまった情報がなく、若干苦戦したのでまとめておきます。

だいたい以下のような動作をします。

  • プラグインのcomposer.jsonの[‘extra’][‘class’]で指定されたPluginInterfaceを実装したClassのactivate()が呼ばれる
  • 同クラスのgetSubscribedEvents()という静的メソッドでイベントを受けるメソッドを指定する
    • post-autoload-dumpなどのイベント名を指定する
  • イベントを受けるメソッドにはイベントオブジェクトが渡ってくるので、なにか処理する

また、基本的にはプラグインなので、他のcomposer.jsonでrequireされない限りイベントは来ません。開発中に試しにイベントを発火させてみたい場合は、他のcomposer.jsonのほうでrepositoriesにtype:pathと指定したものを追加し、そこからプラグインを追加すると簡単に検証できます。

今後の課題

今回、マッチングの部分で妥協して、データ量に問題があるままリリースしてしまったので、そこは早めに修正したいです。

また、現状データ処理に時間がかかっているので、もっと処理を見直していきたいです。