プロダクトコードの静的解析にhorusecを入れた話

この記事はfreee アドベントカレンダー16日目です。

みなさんこんにちは。PSIRTというチームでエンジニアをしているlivaです。PSIRTという聞き慣れない単語ですが「Product Security Incident Response Team」の略で、文字通りプロダクトのセキュリティにフォーカスしたチームです。元はCSIRT(Computer Security Incident Response Team)でまとめてやっていたんですが、今年の夏頃から分かれて動いています。業務内容は今までと何一つ変わっておらず、AWS触ったりGCP触ったりプロダクトチームへセキュリティ関係のことで首突っ込んだりとプロダクトのセキュリティに関することは色々やっています。


さて、今回の話題はタイトル通り「プロダクトコードの静的解析」についてです。 今まで各プロダクトごとにツールが運用されていたりいなかったりで「統一されたなにか」はありませんでした。課題感としては入社してからずっとあったので、PSIRTになったタイミングで統一したものを導入することを決めました。ここではその話をしたいと思います。

1. 持っていた課題感

以前から「プロダクトコードに存在する脆弱性を把握できていない」という課題がありました。出来上がったコードを動作させて脆弱性を探し出す一般的な脆弱性診断の仕組みは整備されていて、リリース前後や定期診断にて脆弱性を検出することはできていました。

しかし、この運用の場合、プロダクトが実際に動作してからチェックされるために、ある程度出来上がった状態で診断を行います。ここで脆弱性が出ると手戻りが大きくなり却ってコストが膨らむことになります。また、仮に根本的な設計変更が必要な脆弱性が検出された場合、リリースが遅れることにもなってしまいます。会社としてもチームとしてもあまりいいとは言えません。またSQLインジェクションやクロスサイトスクリプティング等、コードの書き方次第で発生してしまうことが多い脆弱性は「コードを書いた時点で検出されることが理想」と考えていました。

2. 静的解析とは

コードを動作させずにテストしていく手法です。コードを動かすことがないため、CLI上で動かしやすいです。また、IDEに仕込むタイプのものも数多く存在しているので、コードを書いてる最中にリアルタイムでテストが走り、修正することができます。

Rubyだとrubocop、JavaScriptだとESLintが該当します。各言語に存在するLinterのようなものがイメージしやすいと思います。この記事で話すようなセキュリティツールとしては、RubyのBrakeman、Goのgosecなど、こちらも各言語ごとにツールが存在しています。有償ツールも現在は相当数存在していて、特に海外企業が力を入れているような印象があります。いくつか調査しましたが記事の内容から逸れていくのでここでは割愛します。

ちなみに、こういったセキュリティの静的解析を行うことをSAST(Static Application Security Testing)と呼ぶことがあります。重要用語ではないですが、一単語として覚えていてもらえればなにかのときに役立つかも知れません。

3. 導入することのメリット

いくつかあると思いますが、最大のメリットは「開発工程で見つけることで手戻り工数やコストが減らせる」ことです。最近話題の「Shift Left」という考え方になります。後工程でやっていたことを前工程でやるようにして手戻りを減らし、工数やコストを削減することです。手戻りや後からの差し込み対応を減らすことで開発チーム全体の開発速度向上を見込めます。「チームの生産性向上」というのがいいんでしょうか。抽象的な言葉なのであまり好きではないですが、そういった効果が見込めます。

4. freeeでの導入計画

freeeでは導入するツールを全体で共通化したかったため、選定条件をいくつか出しました。

  1. 主要プロダクト・サービスで使用している言語に対応している
  2. 検出箇所のハイライト機能がある
  3. GitHubにあるプライベートリポジトリに対してスキャンが可能
  4. スキャン対象外リストの作成が可能
  5. ダッシュボード機能がある
  6. 会計フリーをスキャンしても落ちない
  7. CI対応

まず1ですが、弊社の主要プロダクト・サービスはそれぞれで言語が分かれているため、全ての言語に対応しているツールを探す必要があります。「SAST tool」で検索するといくつかでてくるのですが、網羅しているものがなく、これと言ったものをさがすためにかなり苦労しました。

2,3,4は「検出されたけどどこで?」「プライベートリポジトリ対応してないの?」「スキャン対象外リスト作れなかったら過剰検知の対応どうするの?」等の問題が多発するため、セキュリティツール選定においては重要事項です。

5は開発者全体が見れるように共有を行いたかった意図があります。スキャン結果は外部公開するものではないですが、社内に対しては情報統制する必要性はありません。開発者が全体の傾向やどういう対応がされているかの情報を共有できることで出てくるメリットの方が多いと思います。

6は弊社では最重要事項でした。弊社のメインプロダクトである会計フリーで回らなければ価値がないくらいです(当社基準)。しかしリポジトリが巨大すぎて、スキャンを実行すると(ローカルでもEC2上でも)リソースが逼迫して落ちていく事象が発生しました。過去にも有償ツールならさすがに大丈夫だろうと試したところ、2週間経ってもスキャンが終わらないこともありました。「こんな巨大なのを回し切るツールあるのか…?」と思っていましたが、探せばあるものですね。

7は当初からPull Requestで実行するCIジョブの一つとして回す予定があったため条件に追加しています。

以上の条件の他スキャン速度等も含めて検討し評価を実施しました。その中で選んだのはhorusecという海外ツールでした。

5. 具体的にどう入れたか

horusec導入にあたりいくつかフェーズを切りました。

  1. horusec dashboardを立てる
  2. 1次リリースプロダクトのスキャンを実施し脆弱性を洗い出す
  3. horusecの設定を埋め込む
  4. CIジョブとして登録する

1の工程が1ヶ月程度かかりました。公式の構成をそっくりそのままAWS上に構築し、以下の図のようなdashboardを社内限定で公開するようにしています。

f:id:LIVA:20201214143001p:plain
Dashboardイメージ図

全体の構成としては以下の図のようになります。

f:id:LIVA:20201214134041p:plain
freeeでのhorusec構成図

2の工程はすでに何かしらのツールがCIに組み込まれているプロダクトをいくつか選びました。既存脆弱性の修正にかかる工数が少ない(ハズ)というのが一番の理由です。なにもないところにいきなり入れると何が起きるかわかりませんからね。大事です。 手元でhorusecを回し、脆弱性をリストアップした後「これは無視してもOK」「これは修正しよう」というようなトリアージ作業を検出項目に対して行っていきます。同時にhorusecの設定ファイルを作成し、その中にリスクを許容する脆弱性の登録やスキャン対象外ディレクトリの登録等を行っていきます。(3の工程)

4でCIジョブとして登録し、無事スキャンが回り始めたらリリース完了となります。

ここまでを1次リリースとして現在最終段階を進めています。年末までに10プロダクトで稼働する予定です。

6. 諸々余談

ツール導入にあたって社内で「こんなことするよ」って情報を出していたんですが、特に反発はありませんでした。大体セキュリティって言うのは面倒なことが増えるので多少反発あると思ったんですが、そういった声は一切なかったので助かってます。もしかしたら見てないのかもだけどそれは気にしないことにします。

horusecのドキュメントの大枠はポルトガル語で書かれていました。一応公式ページには英語も用意されていますが、GitHub上で細かいところを追い始めると逃げられず、当初は四苦八苦してました。2週間程度翻訳しながら読んでると意外と読めるようになるもので、後半はあまり翻訳を入れることがなくなりました。英語に続きポルトガル語も読めるようになって変なところで成長を感じます。

システム周りの話でいうと、horusecは複数のサービスを立ち上げる必要があり、その相互依存が割と面倒でした。ユーザー管理下で作成することを意図していないのか、ドキュメントが存在しなかったのもあり、トライアンドエラーを繰り返して手探りで構築していました。大体は環境変数や設定ファイルに沿って素直に動作してくれるので、その定義さえ間違えなければOKという状態の作りでした。最近出てきたセキュリティスキャン系のOSSでも扱いやすい存在ですね。


freeeではエンジニアを募集中です。セキュリティに対して一家言ある方、巨大プロダクトのセキュリティに携わりたい方、一緒にやりましょう。 jobs.freee.co.jp

明日はUXデザイナーのはるたんです。最近会計フリーが大幅に変わったんですが、そのあたりの話をしてくれるようです。

お楽しみに。