In this article
JavaScriptの静的解析を始める
JavaScriptコードを書くうえで、静的解析はコードの品質と可読性を保ち、セキュリティを確保するために重要です。静的解析とは、コードの実行前にソースコードを自動でスキャンしてチェックし、深刻なセキュリティ問題やアプリケーションの障害につながる可能性のある、問題のあるコーディングパターンやバグ、脆弱性、エラーを特定するプロセスです。
JavaScriptは動的で柔軟性の高い言語であるため、静的解析は特に有用です。従来型のコンパイラがないことを補い、開発ライフサイクルの早い段階で潜在的な問題を見つけるための手段を開発者に提供します。TypeScriptの導入を検討した理由の一つも、おそらくこれですよね?
静的解析とは
静的コード解析とも呼ばれる静的解析は、プログラムの実行前にソースコードを自動で調べるデバッグ手法です。コードを一連のコーディングルール(または複数のルールセット)に照らして解析します。
静的解析では、ソフトウェアアプリケーションを実行せずに、そのソースコードを検査します。コードを実行して評価する動的解析とは異なり、静的解析は実行時ではない環境で行われます。この手法は、アプリケーションやその機能に悪影響を及ぼす可能性のあるエラー、バグ、その他の問題の発見に役立ちます。また、開発者がコードベースを理解し、コードの品質を確保して、プロジェクト全体でコーディング標準を維持するうえでも有効です。
JavaScriptでは、ESLint、JSHint、TSLintなどのツールを使って静的解析を実行できます。ESLintの動作を簡単な例で見てみましょう。
var user = {};
console.log(user.name);このコードに対してESLintを実行すると、次の警告が表示されます。Unexpected console statement no-console
この警告は、本番コードでconsole.logを使わないよう開発者に促します。これは望ましくないプラクティスとされています。
静的解析と動的解析の比較
静的解析と動的解析を詳しく見ながら、状況によって動的解析より静的解析が有効な理由を確認しましょう。
ESLintを使った静的解析の例を見てみましょう。
const ESLint = require('eslint');
const eslint = new ESLint({ fix: true });
async function lintCode() {
const results = await eslint.lintFiles(["./**/*.js"]);
await ESLint.outputFixes(results);
}
lintCode().catch((error) => {
process.exitCode = 1;
console.error(error);
});
このスクリプトはESLintのプログラマティックAPIを使って、プロジェクト内のすべてのJavaScriptファイルに静的解析を実行し、可能な問題を修正します。
動的解析とは?
一方、動的解析ではアプリケーションの実行中に分析を行います。システムのパフォーマンス、動作、出力をリアルタイムで確認できます。静的解析と異なり、動的解析にはプログラムの実行が必要です。静的解析では見つからない可能性のある実行時の問題を特定するため、デバッグによく利用されます。
ブラウザーまたはNode.jsランタイムでJavaScriptを使う場合、console.time()とconsole.timeEnd()を活用して動的解析を行えます。
function someFunction() {
// Some code here...
}
console.time('someFunction');
someFunction();
console.timeEnd('someFunction');このスクリプトはsomeFunction ()の実行にかかる時間を出力し、簡単な動的解析を実現します。
ネイティブのNode.jsアプリケーションでは、組み込みのnode:perf_hooksモジュールを使って、関数の実行にかかる時間を計測できます。
const { performance } = require('perf_hooks');
function someFunction() {
// Some code here...
}
const start = performance.now();
someFunction();
const end = performance.now();
console.log(`Time taken: ${end - start}ms`);アプリケーションセキュリティでは、実行中のWebアプリケーションを分析するために動的アプリケーションセキュリティテスト(DAST)ツールが使われます。インジェクション攻撃やクロスサイトスクリプティング(XSS)などのセキュリティ上の脆弱性を特定するのに役立ちます。SASTとDASTの違いと、両方を組み合わせる方法について詳しくご覧ください。
状況によって動的解析より静的解析が有効な理由
静的解析と動的解析にはそれぞれ独自の利点があり、コードの品質とセキュリティを確保するため、ソフトウェア開発ライフサイクルのさまざまな段階で併用されることがよくあります。ただし、状況によっては静的解析が動的解析より明確に優れています。
バグの早期発見:静的解析はコードを書いた直後から実行できるため、テストを始める前であっても、開発サイクルの早い段階で問題を発見して修正できます。これにより、大幅な時間短縮とコスト削減につながります。
コード全体を網羅:特定の実行で実行されたコード部分だけをテストする動的解析とは異なり、静的解析ツールはコードベース全体をスキャンします。
コーディング標準の徹底:静的解析ツールはコーディング標準とベストプラクティスを徹底できます。逸脱を検出するよう設定できるため、コード品質の一貫性を維持できます。
JavaScriptで静的解析を活用する
インタラクティブなWebアプリケーションの作成によく使われるJavaScriptは、動的で弱い型付けの言語です。つまり、JavaScriptの変数は型チェックによる制約を受けず、どのような型の値でも保持できます。この柔軟性は、見つかりにくいバグや脆弱性につながることもあります。
たとえば、次のJavaScriptコードを見てみましょう。
function addNumbers(a, b) {
return a+b;
}
console.log(addNumbers(1, 2));
// Outputs: 3
console.log(addNumbers(1, "2"));
// Outputs: "12"上記の例では、addNumbersは2つの数値を加算するように設計されています。しかし、JavaScriptの緩やかな型システムにより、文字列と数値も連結してしまいます。これは意図した動作ではない可能性が高いでしょう。この例から、JavaScriptにおける静的解析の重要性がわかります。
JavaScriptのコードセキュリティを維持するうえで、静的解析は不可欠です。悪意ある攻撃者に悪用される可能性のある、コードに潜むセキュリティ上の脆弱性を発見できます。サイバーセキュリティの重要性が高まるなか、開発プロセスで静的解析ツールを使うことは、選択肢ではなく必須事項です。
静的解析でJavaScriptのコード品質とセキュリティを高める方法
コード品質
静的解析はコーディング標準やスタイルの徹底に役立ち、コードの一貫性を高め、読みやすく理解しやすくします。また、未使用の変数や到達不能なコード、冗長な条件式などの潜在的な問題も検出し、コードをよりクリーンで効率的にできます。
たとえば、次のJavaScriptコードを見てみましょう。
let x;
if (x = 10) {
console.log("x is 10");
} else {
console.log("x is not 10");
}このコードに対してESLintを実行すると、次のエラーが表示されます。Expected a conditional expression and instead saw an assignment no-cond-assign
このエラーは、比較演算子ではなく代入演算子である単一の等号を使ってしまう、といったよくあるミスを防ぐのに役立ちます。
コードセキュリティ
静的解析ツールは、インジェクション攻撃やクロスサイトスクリプティング(XSS)、安全でない乱数生成など、幅広いセキュリティ上の脆弱性を検出できます。こうした脆弱性を自動でチェックできるため、手動のコードレビューよりもはるかに効率的で信頼性の高い方法です。
たとえば、次のNode.jsコードを見てみましょう。
const express = require('express');
const Sequelize = require('sequelize');
const access_token = 'a_sample_token';
const app = express();
const sequelize = new Sequelize('database', 'username', 'password', {
dialect: 'sqlite',
storage: 'data/juiceshop.sqlite'
});
app.post('/login', function (req, res) {
sequelize.query('SELECT * FROM Products WHERE name LIKE ' + req.body.username);
});
app.get('/test', function(req,res) {
const test = null;
const dog = test?.dog;
console.log(dog);
});
app.get('/some/path', function(req, res) {
res.redirect(req.param("target"));
});
window.addEventListener("message", (event) => {
console.log(event.data);
});ここにある脆弱性をすべて見つけられますか?
Snykを使えば簡単に見つけられます。IDEにSnyk VS Code拡張機能をインストールするだけで、コードのセキュリティに関するフィードバックをリアルタイムで受け取れます。ファイルを保存すると、リンターのようにSnykのセキュリティ解析結果がエディターに表示されます。
このコードに対してSnykを実行すると、次の警告が表示されます。
コード内でアクセストークンにハードコードされたシークレットが使われています
/some/pathルートにおけるオープンリダイレクトの脆弱性

実は、ほかにもいくつか問題が潜んでいます。見つけてみませんか?Snykの無料アカウントに登録して、ぜひお試しください!
抽象構文木(AST)入門
抽象構文木(AST)は、プログラミングとコードセキュリティにおける重要な概念です。プログラミング言語で書かれたソースコードの抽象的な構文構造を、木構造で表現したものです。各ノードはソースコード内に登場する構文要素を表します。
JavaScriptの静的解析では、抽象構文木が中心的な役割を果たします。静的解析とは、コードを実行せずに調べることです。コードレビューを自動で行うようなもので、潜在的なバグや脆弱性、コーディング規約違反をスキャンします。ASTはソースコードを構造化し、たどりやすい形で表現するため、このプロセスに欠かせません。ASTを使うことで、静的解析ツールはコードを効率よくたどり、バグやセキュリティ上の脆弱性を示すパターンを特定できます。
次のJavaScriptコードを見てみましょう。
function greet (name) {
return `Hello, ${name}!`;
}簡略化したASTは次のようになります。
Program
FunctionDeclaration
Identifier (name: greet)
BlockStatement
ReturnStatement
TemplateLiteral
TemplateElement (value: Hello, )
Identifier (name: name)
TemplateElement (value: !)この表現により、静的解析ツールはコードの構造と流れを理解し、潜在的な問題を見つけやすくなります。
AST ExplorerでJavaScriptコードの構造を理解する
AST Explorerは、コードが抽象構文木にどのように変換されるかを理解するのに役立つ強力なツールです。JavaScriptを含むさまざまな言語に対応しており、ASTに関連する問題の学習やデバッグに最適です。
JavaScriptでAST Explorerを使うには、次の手順に従ってください。
AST Explorerにアクセスします。
上部のメニューで、言語として「JavaScript」を選択します。
左側のペインにJavaScriptコードを貼り付けるか、入力します。
右側のペインが自動的に更新され、入力したコードのASTが表示されます。
たとえば、先ほどの例にあるgreet関数を入力すると、次のようになります。
function greet (name) {
return `Hello, ${name}!`;
}対応するASTが右側のペインに表示されます。コードの木構造を確認し、たどっていくことで、コードがどのように解釈されるかをより深く理解できます。

ASTを理解することは、JavaScriptの静的解析を習得するうえで重要です。コードの構造、JavaScriptエンジンによる読み取り方、静的解析ツールによる解釈について、貴重な洞察が得られます。この知識は、より効率的で安全な、バグのないコードを書くのに役立ちます。
JavaScript向け静的解析ツール3選
静的解析ツールは、コードを実行せずに解析します。そのため「静的」と呼ばれます。ソースコードをパースして抽象構文木(AST)を構築し、コードの構造や意味を理解します。そのうえで、ASTにさまざまなルールやヒューリスティクスを適用し、潜在的な問題を検出します。
JavaScript向けの静的解析ツールには、広く使われているものがいくつかあります。ここでは、その一部を紹介します。
1. Snyk Code
Snyk Codeは、CLI、IDE、またはGit連携を通じて利用できる、セキュリティに特化した静的解析ツールです。標準的な静的解析機能に加え、Symbolic AIを活用した高度なコード解析を提供します。これにより、ほかのツールでは見逃される可能性のある、複雑で複数のステップにわたる脆弱性も検出できます。
静的解析でよくあるセキュリティ問題であるSQLインジェクションを特定する方法を、例を使って見てみましょう。次のJavaScriptコードを確認してください。
let query = "SELECT * FROM users WHERE name = '" + userInput + "'";上記のコードでは、userInputがSQLクエリに直接連結されています。攻撃者がuserInputを制御できる場合、クエリを改変して機密情報を抜き出したり、悪意ある操作を実行したりする可能性があります。Snykのような静的解析ツールは、このパターンを潜在的なSQLインジェクションの脆弱性として警告できます。
Snyk Codeを使うには、Snykの無料アカウントに登録してSnyk CLIをインストールするか、Snyk VS Code拡張機能を使って、コードのセキュリティに関するフィードバックをリアルタイムで受け取ります。
npm install -g snyk
snyk auth
snyk test上記のコマンドでは、Snyk CLIをインストールし、Snykアカウントで認証してから、コードに対してSnykのテストを実行しています。
2. JavaScriptの静的解析に使うESLint
ESLintは、JavaScriptコードのスタイルに関する問題や潜在的なバグ、セキュリティ上の脆弱性をチェックします。プラグイン可能なアーキテクチャを採用しており、開発者が独自のルールを定義して使用できます。
ESLintはコードのパターンを解析し、未使用の変数や到達不能なコード、セミコロンの欠落など、バグや一貫性の欠如につながる可能性のある問題を知らせます。定義したルールセットに照らしてコードをパースし、チェックすることでこれを実現します。
ESLintの基本的な.eslintrc.json設定ファイルは次のとおりです。
{
"extends": ["eslint:recommended", "plugin:security/recommended"],
"plugins": ["security"],
"rules": {
"security/detect-sql-injection": "warn"
}
}上記の設定では、ESLintの推奨ルールとセキュリティプラグインの推奨ルールを拡張しています。また、SQLインジェクションの潜在的な脆弱性に対する警告も有効にしています。
ESLintは、インデント、セミコロンの使用、行の長さ、文字列にシングルクォートとダブルクォートのどちらを使うかなど、幅広いスタイルルールを適用するよう設定できます。たとえば、インデントにスペース2つを使いたい場合、そのルールに従っていないコードを検出したときにESLintが警告するよう設定できます。
さらに、ESLintはよくあるミスやコード内の潜在的な問題を知らせ、エラーの防止にも役立ちます。開発ワークフローにESLintを組み込めば、エラーが本番環境に入り込む前に検出して修正できます。
3. Prettier
Prettierは、独自の方針に基づいてコードを整形するオープンソースのJavaScriptライブラリです。コードベースやプロジェクト全体で、一貫したコーディングスタイルを適用できます。開発者なら、コードスタイルをめぐる意見の違いに気を取られ、本当に重要なことに集中できなくなる経験があるかもしれません。Prettierに整形を任せれば、見た目を気にせずコードを書くことに集中できます。
PrettierはJavaScript、TypeScript、CSS、HTML、Markdownなど、多くの言語に対応しています。ほとんどのエディターと連携し、すぐに使い始められるため、複雑な設定ファイルの構成に時間をかける必要はありません。Prettierは、先ほど説明した抽象構文木(AST)にコードを解析し、整形ルールを適用してから、整形後のコードを出力します。
Prettierで整形する前と後のコードの例を見てみましょう。
Prettier適用前:
let foo=function( arg1, arg2 ) {
if (arg1>arg2) {
return arg1
} else {
return arg2
}
}Prettier適用後:
let foo = function(arg1, arg2) {
if (arg1 > arg2) {
return arg1;
} else {
return arg2;
}
};ご覧のとおり、Prettierはスペースや括弧の位置を統一し、return文の末尾にセミコロンを追加しています。
Prettierがコードの整形だけに特化しているのに対し、ESLintは、エラーにつながる可能性のあるJavaScriptコードのパターンをチェックするツールです。ESLintは柔軟に設定でき、特定のコーディング標準や規約を適用するよう細かく調整できます。
PrettierとESLintが互いを補い合うのはこの点です。Prettierがコードを一貫した形式に整える一方で、ESLintはコードがベストプラクティスに準拠しているか、潜在的なバグが含まれていないかを確認します。この2つのツールを併用すれば、コードの品質を大きく向上できます。
エディターでファイルを保存するたびにPrettierでコードを整形し、ESLintで潜在的な問題をチェックするよう設定することもできます。こうすれば、問題が深刻化する前に検出して修正できます。
.eslintrc.jsonファイルで設定する例を見てみましょう。
{
"plugins": ["prettier"],
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
"rules": {
"prettier/prettier": "error"
}
}この設定では、ESLintの推奨ルールを継承し、プラグインとしてPrettierを追加しています。また、prettier/prettierルールをエラーに設定しています。つまり、コードがPrettierの整形ルールに準拠していない場合、ESLintがエラーを出します。
JavaScriptアプリのセキュリティ対策を始めましょう
Snykを無料で利用して、JavaScriptの脆弱性を検出・修正しましょう。
クレジットカードは不要です。
またはAzure AD Docker ID Bitbucketで登録
Snykを利用することで、利用規約およびプライバシーポリシーを含む当社の各種ポリシーに同意したものとみなされます。