SASTツールのスキャン速度を比較:Snyk Code、SonarQube、LGTM
Frank Fischer
2021年7月22日
0 分で読めますSnyk Codeと、代表的な2つのSASTツールであるLGTMおよびSonarQubeのスキャン時間を比較してほしいというご要望をいただきました。調査ではいくつかの前提を置きましたが、透明性を確保するため、その詳細も公開しています。
要約
静的アプリケーション・セキュリティ・テスト(SAST)が開発者にとって使いやすいものであるためには、ほぼリアルタイムのフィードバックを提供し、開発プロセスを遅らせないことが重要です。Snyk CodeはLGTMより最大106倍高速です。平均すると、Snyk CodeはSonarQubeより5倍、LGTMより14倍高速です。つまり、Snyk Codeは市場最速クラスのセマンティックスキャンエンジンの1つです。
テスト環境
JavaScriptのオープンソースリポジトリを48件選びました(以下に一覧を掲載)。現代の開発者が一般的に扱うコードセットを再現することを目的とし、共通の比較対象としてJavaScriptが適していると考えました。実際の課題を反映できるよう、GitHubで評価の高いリポジトリから無作為にサンプルを選んでいます。
スキャナーには、広く使われているオープンソースの静的解析ツール、SonarQube Community Editionを使用しました。ローカルで実行するため、十分な性能のPCが必要でした。無料のSonarCloudエディションを使った過去のテストでは、性能の良いPC上のSonarQubeのほうが高速でした。そのため、クラウド版ではなくローカルエンジンを使うのは不公平ではありません。既存の開発者用マシンを1台使う必要がありました(詳細は後述)。もう1つの比較対象はLGTMです。LGTMはSemmleという企業が開発し、同社はGitHubに買収されました。LGTMはCodeQLをベースにした深いセマンティックコード検索を使用します。LGTMのSaaSサービスを利用しました。
最後に、Snyk CodeはSnykのSASTソリューションです。旧DeepCodeスキャンエンジンをベースに、Snykで数か月にわたり追加開発を重ねています。開発者にとって使いやすく、高精度であることに加え、Snyk Codeの設計目標の1つは非常に高速であることです。独自の制約エンジンによってこれを実現しています。今回の比較対象を選んだ理由は、(1)ライセンス上、実行して比較できる、(2)リンター(ESlintなど)ではなくセマンティックエンジンである、(3)一般的に広く使われているエンジンである、(4)ローカル実行型とSaaSの両方が含まれている、という点です。
SASTソリューションが開発者にとって使いやすいものになるには、速度が不可欠です。開発者は、セキュリティ上の問題を開発プロセス中に特定し、コードをチェックインする前に修正できると、最も効率的に作業できます。コードを書いたときの記憶も新しいからです。Snyk Codeは、開発者のワークフローにシームレスに組み込めるIDEプラグインを提供します。さらに、理解しやすいデータフロー図や詳しい説明に加え、同じコンテキストのオープンソースライブラリで使われている修正例も提示します。ただし、今回のテストでは速度に焦点を当てました。
テストでは、各リポジトリをスキャンしました。SonarQubeはローカルで、LGTMとSnyk CodeはSaaSとして実行しました。前述のとおり、ネットワーク帯域幅によってスキャン時間が左右されないように、リポジトリを選定しています。
また、ベンチマークではなく実際のオープンソースリポジトリを選びました。実際の開発者の作業を再現することが目的だからです。ベンチマークを使ってSASTツールを比較することには固有の問題がありますが、今回の目的には適していません。
テスト結果
スキャン時間(秒)の基本統計量を以下に示します(n=48、整数に四捨五入):
平均 | 最大 | 最小 | 5パーセンタイル | 95パーセンタイル | 中央値 | 標準偏差 | |
|---|---|---|---|---|---|---|---|
SonarQube | 110 | 895 | 63 | 63 | 257 | 77 | 127 |
LGTM | 312 | 1835 | 2 | 141 | 1046 | 189 | 352 |
Snyk Code | 22 | 162 | 5 | 5 | 72 | 12 | 28 |
散布図にした結果は以下のとおりです(値が小さいほど良好、対数目盛、Rとggplot2で作成)。

対数軸では、値の小さい範囲のばらつきが強調されます。たとえば、Snyk Codeの標準偏差はSonarQubeより実際にはかなり小さい値です。
以下は値を箱ひげ図にしたものです(値が小さいほど良好。すべての値をグラフに収めるため対数目盛を使用。Rとggplot2で作成。中央値と平均値を表示)。

このグラフから、ほとんどの場合にSnykが他の2つのツールより圧倒的に高速であることが明確にわかります。Snykの中央値はSonarQubeより6.7倍、LGTMより最大16.4倍高速です。つまり、非常に良い外れ値だけに左右された結果ではなく、全般的な傾向を示しています。
上の図で注目すべきなのは、LGTM列の値のばらつきです。おおよそ2分(なんとか許容範囲)から17分超(許容できない範囲)に及びます。開発者が作業中に数分かかる結果を待つことはありません。幸い、LGTMの中央値は約3分です。
前回の速度テスト(当時はDeepCode、現在のSnyk Code)と比べると、ここ数か月でクラウドサービスへの読み込みを大幅に最適化したため、パフォーマンスが大きく向上していました。また今回は、前回より高性能で並列処理能力の高いPCを使ったためか、SonarQubeも高速になりました。
もう1つ興味深い点は、速度の観点では、SaaSエンジンとローカルにインストールしたエンジンにそれほど大きな違いがないことです。
前提と制限事項
SonarQube(Community Edition 8.9.1)とLGTMは、ライセンス上この比較が可能で、広く使われているため選定しました。
一般的な開発者の作業を反映すると考え、中規模のJavaScriptリポジトリを48件選びました。GitHubでスター数上位約20万件のリポジトリから無作為にサンプルを抽出しました。コードサイズは選定基準にしていません。
差分スキャンは使わず、フルスキャンを実行しました。たとえばSnyk CodeのIDEプラグインでは、初回スキャンの後に差分スキャンを行い、帯域幅を節約します。
Intel Xeon @ 2GHz、16コア、64GB RAMを使用
最先端のインテリジェンスでコードを保護
わずか30分で、Snyk CodeのSAST機能を幅広くご紹介します。
生データ
独自の統計分析に利用できるよう、生データも公開します(時間は秒)。
リポジトリ | SonarQube | LGTM | Snyk Code |
|---|---|---|---|
neumino/chateau | 101 | 259 | 9 |
ecomfe/etpl | 80 | 237 | 24 |
ustwo/ustwo.com-frontend | 77 | 278 | 20 |
node-inspector/node-inspector | 157 | 373 | 21 |
q-nick/npm-gui | 71 | 227 | 8 |
dojo/dojox | 317 | 662 | 53 |
majimboo/node-benchmarks | 63 | 141 | 5 |
prettier/prettier | 84 | 277 | 45 |
d3/d3.github.com | 895 | 1104 | 67 |
adobe/node-smb-server | 79 | 194 | 13 |
noble/bleno | 66 | 141 | 5 |
wagtail/wagtail | 115 | 1462 | 56 |
meteor/blaze | 83 | 194 | 12 |
dwyl/hapi-socketio-redis-chat-example | 68 | 141 | 5 |
chancancode/hn-reader | 64 | 165 | 20 |
shipshapecode/ember-shepherd | 82 | 152 | 30 |
draptik/angulardemorestful | 76 | 163 | 6 |
icebob/vue-express-mongo-boilerplate | 77 | 422 | 9 |
ngryman/ribs | 64 | 193 | 7 |
rjrodger/seneca-examples | 70 | 176 | 12 |
telepat-io/telepat-api | 68 | 173 | 8 |
sematext/logagent-js | 68 | 162 | 8 |
cookpad/elasticfox-ec2tag | 87 | 173 | 11 |
polonel/trudesk | 170 | 1835 | 77 |
saintedlama/passport-local-mongoose | 72 | 173 | 7 |
cholalabs/passport-localapikey | 63 | 3 | 5 |
mozilla/openbadger | 79 | 184 | 20 |
inbasic/turbo-download-manager | 94 | 206 | 31 |
pgherveou/gulp-awspublish | 65 | 152 | 5 |
swagger-api/swagger-socket | 93 | 746 | 7 |
tactivos/jquery-sew | 69 | 225 | 5 |
johansatge/jpeg-autorotate | 63 | 152 | 6 |
mqttjs/mqtt-packet | 65 | 173 | 12 |
fulcrum-agile/fulcrum | 80 | 152 | 18 |
microweber/microweber | 300 | 937 | 162 |
adamhalasz/uniqid | 68 | 151 | 5 |
componentjs/builder2.js | 71 | 142 | 8 |
frankyghost/projekktor | 92 | 195 | 9 |
nielsutrecht/jwt-angular-spring | 88 | 288 | 8 |
petereigenschink/steganography.js | 69 | 141 | 5 |
mixteam/mixsln | 75 | 205 | 48 |
borismus/webvr-boilerplate | 70 | 213 | 42 |
arrix/node-readability | 77 | 152 | 19 |
iamcal/js-emoji | 72 | 412 | 6 |
jbavari/ionic-socket.io-redis-chat | 149 | 384 | 19 |
cheeaun/steepless | 69 | 142 | 5 |
joewalker/devtools.html | 177 | 2 | 74 |
gaearon/react-hot-loader | 80 | 162 | 15 |