JavaScript
セキュリティ
脆弱性診断
retirejs

脆弱性のあるJavaScriptライブラリを検出するRetire.jsを紹介

Webには時代遅れで脆弱性のあるJavaScirptライブラリで溢れていることが研究により明らかに」という記事のとおり、世の中には脆弱性のあるJavaScriptライブラリを使った多くのウェブサイトが存在します。

IPAが公開している「安全なウェブサイトの作り方」には脆弱性が修正されたバージョンのライブラリを使用する。と記述があったり、「OWASP TOP10 2017 (日本語版)」にも既知の脆弱性のあるコンポーネントの使用を避けるように、と脆弱性のあるライブラリを使用しないよう注意喚起されています。

脆弱性のあるライブラリを使用しているか調べることができるRetire.jsを紹介します。
すべての脆弱性を防げる保証は無いので、あくまで自己責任でお使いください。

Retire.jsとは

スクリーンショット 2018-03-22 03.08.49.png

Retire.jsは上の画像のようにCLIなどで実行することができる脆弱性のあるJSライブラリを検出するツールです。

Retire.jsのページにはThe goal of Retire.js is to help you detect the use of JS-library versions with known vulnerabilities.と記述されています。
拙い訳ですが、「Retire.jsは脆弱性があることがわかっているJSライブラリを検知する補助を行うことを目的としています。」という意味です。
Retire.jsのページにRetire.jsが検知する脆弱性の一覧が掲載されています。

Retire.jsの使い方

使用方法はRetire.jsのGitHubに掲載されています。
npmでインストールしてCLIやgulp・gruntで実行することができます。
ChromeやFirefoxのエクステンションも提供されています。

CLI

まずはnpmのretire.jsを使用しコマンドラインから実行する方法を紹介します。
gulpから実行したい方やChromeやFirefoxのエクステンションで実行したい方は読み飛ばして下さい。

インストール

npmでretireというパッケージをインストールする必要があります。
Retire.jsをローカルにインストールせずに使いたい方は後述があるのでインストール手順は読み飛ばして下さい。

グローバルにインストールする場合
$ npm install -g retire
プロジェクトのnode_modulesにインストールする場合
$ npm install --save-dev retire

調べたいプロジェクトの直下に移動して実行します。

グローバルにインストールした場合
$ retire
node_modulesにインストールした場合
// package.jsonのscriptsに以下を追記
{
  "scripts": {
    "retire": "retire"
  }
}

// CLIで実行
$ npm run retire

脆弱性のあるライブラリがある場合、以下のような内容がコンソールに表示されます。
以下はlodash 1.0.2に脆弱性があるのを検知した例です。

{package.jsonに記載されているname} 0.0.0
↳ lodash 1.0.2
lodash 1.0.2 has known vulnerabilities:  severity: low; summary: Prototype pollution attack; https://hackerone.com/reports/310443

npmのバージョン5.2以上をお使いでローカルにインストールせずに使いたい方はnpxを使って実行することができます。
npxについては「npm 5.2.0の新機能! 「npx」でローカルパッケージを手軽に実行しよう」に詳しく紹介されています。

npxで実行
$ npx retire

gulp

gulpのタスクとして定義して実行することも可能です。
gulpについては「Gulp.js入門」をご覧ください。
Retire.jsのGitHubに掲載されている例を元に紹介します。
gulpで実行する場合もretireをnpmでインストールする必要があります。

gulpfileに以下のようなretireというタスクを書きます。タスク名は任意なのでお好きな名前に変更してください。

gulpfile.js
const gulp = require('gulp');
const spawn = require('child_process').spawn;
const gutil = require('gulp-util');

gulp.task('retire', function() {
  var child = spawn('retire', [], {cwd: process.cwd()});

  child.stdout.setEncoding('utf8');
  child.stdout.on('data', function (data) {
    gutil.log(data);
  });

  child.stderr.setEncoding('utf8');
  child.stderr.on('data', function (data) {
    gutil.log(gutil.colors.red(data));
    gutil.beep();
    process.exit(1);
  });
});

Retire.jsのGitHubに掲載されているコードとの違いはprocess.exit(1)で異常終了させているところです。こうすることでnpm-scriptsで複数タスクを実行する場合に異常終了したら以降の処理を行わないように制御することができます。

CLIに比べてgulpにすることのメリットは、脆弱性のあるライブラリがあった場合の処理を追加できるところです。
上記のgulpタスクの場合だと、gutil.colors.red(data)でコンソール上のメッセージを赤く表示します。

Chrome・Firefoxエクステンション

ChromeやFirefoxのエクステンションとしても使うことができます。
以下からダウンロードしてお使いください。
* Chromeエクステンション
* Firefoxアドオン

こちらは他の開発者が開発したウェブサイトを検査するときにも使えます。
例えば、Wikipediaでは以下のような結果が出ました。

スクリーンショット 2018-03-22 02.50.09.png

応用例

筆者が実際行っている応用例を紹介します。

公開前にチェックする

pre-pushpre-commitと組み合わせれば、git commitgit pushしたときに脆弱性のあるライブラリがあればコミットやpushを行わないように制御することができます。

package.json
{
  "scripts": {
    "retire": "retire"
  },
  "pre-commit": ["retire"]
}

package.jsonに記載されているライブラリだけチェックする

Retire.jsはデフォルトではnode_modules以下もすべて検査します。
package.jsonに記載されたライブラリだけ検査したい場合は-pオプションを付けて実行します。

CLIの場合
$ retire -p
gulpの場合
gulp.task('retire', function() {
  // 第二引数の配列にオプションを指定する
  var child = spawn('retire', ['-p'], {cwd: process.cwd()});

  child.stdout.setEncoding('utf8');
  child.stdout.on('data', function (data) {
    gutil.log(data);
  });

  child.stderr.setEncoding('utf8');
  child.stderr.on('data', function (data) {
    gutil.log(gutil.colors.red(data));
    gutil.beep();
    process.exit(1);
  });
});

CIで実行する

GitHubとjenkinsやCircle CIなどCIツールを連携させて、pushされたときときに実行することも可能です。
GitHubとjenkinsの連携については「GithubからJenkinsへのServer Hook」や「Jenkinsでプルリクエストをビルドする」を参考にしてください。

まとめ

  • 簡単に脆弱性のあるライブラリの使用を検出できる
  • コミット前やデプロイ前に検査することで脆弱性のあるライブラリの使用を防止することができる
  • 世の中のウェブサイトの脆弱性の検査をすることができる(悪用厳禁!)
  • すべての脆弱性を防げるかはわからないので、これだけに頼らないこと!

 参考

最後までお読み頂きありがとうございました。
不備や質問はコメント欄かTwitter(@shisama_)などでご連絡ください。