対象:Express(Node.js)でAPIやアプリを運営している人。ここでは攻撃手順は扱わず、最小フレームワークに自分で足す守りを、本番向けの実務リファレンス(優先度つきチェックリスト・領域別対策・自己検証)として示します。全体像は フレームワーク別セキュリティの入口 も参照。
優先度つきハードニング・チェックリスト
まずこの表を上から実施します。P0は前提、P1が最頻の事故源、P2は継続的な運用衛生です。
P0 ── 前提(まずこれ)
ヘッダ(helmet)+x-powered-by無効 / 依存(npm)CVE監視 / 秘密を環境・スタック非露出
P1 ── 最頻の事故源
入力検証とインジェクション対策 / 所有者スコープの認可
P2 ── 運用衛生
レート制限・サイズ上限 / セッション・Cookie・CSRF / SSRF
| 優先 | 対策 | 具体(Express) |
|---|---|---|
| P0 | セキュリティヘッダ | helmet相当で CSP/HSTS/X-Content-Type 等。x-powered-by を無効化 |
| P0 | 依存(npm)CVE | npm audit/osv-scanner で監視・実稼働版で判定し即パッチ |
| P0 | 秘密とエラー | 秘密は環境変数から。本番でスタックトレースを外部に出さない |
| P1 | 入力検証 | 受け取り値を検証・サニタイズ(型・範囲・許可値)。ボディサイズ上限 |
| P1 | インジェクション | DBはバインド。NoSQLの演算子注入($)に注意。eval に入力を渡さない |
| P1 | 認可 | 認証+各ルートで所有者スコープの認可。JWTは署名検証・alg固定 |
| P2 | レート制限 | ログイン/APIに試行/流量の制限。総当り・濫用・DoSを抑える |
| P2 | セッション/Cookie | secure/httpOnly/sameSite。CSRF(Cookieセッション時)。本番用セッションストア |
| P2 | SSRF | サーバー側の外部取得は許可先限定+内部IP/メタデータ遮断 |
1. セキュリティヘッダと露出削減(P0)
Expressは既定でセキュリティヘッダを付けません。まずここを底上げします。
- helmet相当のミドルウェアで CSP・HSTS・X-Content-Type-Options・frameguard 等を付与する。
x-powered-byを無効化し、フレームワーク/バージョンの露出を減らす。- 自サイトの状態は セキュリティヘッダ診断 で確認できる。
2. 依存(npm)とサプライチェーン(P0)
- 依存の既知CVEを
npm auditや osv-scanner で機械監視し、実稼働版で判定して即パッチ(→ 依存のCVE監視)。 - Nodeは依存数が多く、供給連鎖リスク(typosquatting・
postinstallフック等)もある。導入時に吟味し、数を絞る。 - Node をサポート対象(LTS) に保ち、EOL版を放置しない。
3. 入力検証とインジェクション(P1)
- すべての入力(ボディ・クエリ・パラメータ・ヘッダ)を検証・サニタイズする。ボディサイズの上限を設けDoSを抑える。
- SQLはプレースホルダでバインドし、文字列連結でクエリを組まない(→ SQLインジェクションとは)。
- NoSQLでは、オブジェクト型の入力による**演算子注入(
$)**に注意する(クエリに生オブジェクトを渡さない)。 eval等の危険な評価に外部入力を渡さない。
4. 認証と認可(P1)
やりがち(危険)
- 認可を書かず「ログイン=実行可」
- ミドルウェアの順序/存在だけに依存
- IDやフラグをクライアントから来たまま信用
- JWTの署名未検証・
alg:none許容
正しい
- 認証に加えて各ルートで所有者スコープの認可
- 認可はデータに近い場所で確認(順序頼みにしない)
- サーバー側で再検証(IDの差し替えに耐える)
- JWTは署名検証必須+alg固定(
alg:none拒否)
用語は IDORとは / JWTとは。JWTの内容は自分で検査できる(JWTデコーダ)。
5. レート制限と濫用対策(P2)
- ログイン・API・パスワードリセットに試行/流量の制限をかけ、総当りや濫用・DoSを抑える。
- リクエストボディやアップロードのサイズ上限を設ける(大きなペイロードによる枯渇を防ぐ)。
6. セッションと Cookie(P2)
- セッションCookieに
secure/httpOnly/sameSiteを設定する。 - Cookieセッションのアプリは CSRF対策を入れる(→ CSRFとは)。
- 本番では適切なセッションストアを使う(既定のインメモリは本番不可)。ログイン時にセッションを再生成する。
7. SSRF とサーバー側の外部取得(P2)
- サーバーがユーザー指定URLを取得する処理は許可先を限定し、接続時に内部IP/クラウドのメタデータへの到達を遮断する(→ SSRFとは)。
8. エラー処理と本番設定(P0〜P2)
- 集中エラーハンドラで例外を処理し、スタックトレースやスタック情報を外部に出さない。
NODE_ENV=productionで動かす。プロキシ配下ではtrust proxyを正しく設定し、スキームやクライアントIPを誤認しないようにする。- TLS/HTTPS を終端で確実に。
検証:自分のExpressは固められているか
作ったら終わりでなく、点検して初めて完了です。以下は自分の環境に対する防御的な自己チェックです。
ヘッダと露出
x-powered-by が消えていることを ヘッダ診断で確認。エラーで内部が出ないか
認可が効くか
依存とレート制限・SSRF
npm audit/osv がクリーンか、ログインにレート制限が効くか、外部取得が内部IPへ到達しないかを確認。当サイトの視点:最小フレームワークは『自由と責任』がセット
Expressの良さは軽さと自由度ですが、それは守りも自分で設計するという意味です。RailsやLaravelが既定で守る部分(ヘッダ・CSRF・認可の足場)を、Expressでは意識して組み込みます。守りの重心は、上の表を上から潰し、ヘッダを付け・入力を検証し・公開入口に認可を書き・依存をCVE監視すること。とくにNodeは依存の数が多く、依存の鮮度が事故を分けます。「フレームワークが守ってくれるはず」という前提を捨て、防御を明示的に足すのが正しい使い方です。
次に読む
- 入口:フレームワーク別セキュリティ(入口) / Next.jsのセキュリティ対策(同じNode系)
- 実務:依存のCVE監視 / 脆弱性(CVE)対応の実務
- 用語:IDORとは / SSRFとは / JWTとは / CSRFとは
- ツール:セキュリティヘッダ診断 / JWTデコーダ
よくある質問
QExpressで最初にやるべきセキュリティ対策は何ですか?
優先度P0の3つです。(1)helmet相当でセキュリティヘッダ(CSP/HSTS等)を付け、x-powered-by を無効化する、(2)依存(npm)のCVEを機械監視し実稼働版で判定して即パッチする、(3)秘密を環境変数から読み、本番でエラーのスタックトレースを外部に出さない。Expressは既定でこれらを守ってくれないため、自分で足すのが前提です。次に入力検証・認可・レート制限へ進みます。
Qhelmet のようなセキュリティヘッダは必要ですか?
はい。Expressは既定でセキュリティ関連のHTTPヘッダを付けません。helmet相当のミドルウェアで CSP・HSTS・X-Content-Type-Options 等を付与し、クリックジャッキングやMIMEスニッフィング等の初歩的リスクを下げます。あわせて x-powered-by を無効化してフレームワークの露出を減らします。付けるだけで底上げになるので最初に入れる価値があります。
Q認証と認可はどう組みますか?
認証ミドルウェアでログインを確認したうえで、各ルートで『対象が本当にその利用者のものか』という所有者スコープの認可を必ず書きます。ミドルウェアの順序や存在だけに頼らず、データに近い場所で確認するのが安全です。JWTを使う場合は署名検証を必須にし、alg を固定(alg:none を拒否)します。
Q依存パッケージ(npm)の脆弱性はどう管理しますか?
npm audit や osv-scanner で既知CVEを機械監視し、『実稼働版』で判定して素早くパッチします。Nodeは依存の数が非常に多く、供給連鎖(typosquatting・postinstall等)のリスクもあるため、依存の鮮度と導入時の吟味が事故を分けます。Node をサポート対象バージョン(LTS)に保つこともあわせて行います。
Q最低限、何をすればいいですか?
(1)helmet相当のヘッダ+x-powered-by無効化、(2)すべての入力を検証・サニタイズ、(3)所有者スコープの認可、(4)ログイン/APIにレート制限+ボディサイズ上限、(5)依存(npm)のCVE監視+即パッチ、(6)本番でエラーのスタックを外部に出さない。この最小セットで、最小フレームワークの穴の大半を埋められます。