今日のデジタル環境では、Node.js アプリケーションのセキュリティを確保することが最も重要です。 Netflix や Uber のような世界的リーダーから、次の大きなものを構築するスタートアップまで、Node.js は最も要求の厳しい高性能アプリケーションの一部を支えています。ただし、アプリケーションの脆弱性は、不正アクセス、データ侵害、ユーザーの信頼の喪失につながる可能性があります。
このガイドは、実践的なセキュリティの実践と OWASP Web セキュリティ テスト ガイド (WSTG) の重要な概念を組み合わせて、Node.js アプリケーションの強化に役立ちます。リアルタイム操作を管理している場合でも、数百万のユーザーに拡張している場合でも、この包括的なリソースにより、アプリケーションの安全性、信頼性、回復力が確保されます。
情報収集 は、多くの場合、攻撃者がアプリケーションについて詳しく知るために行う最初のステップです。収集できる情報が増えるほど、脆弱性を特定して悪用することが容易になります。
デフォルトでは、Express.js にはサーバーに関する情報が誤って公開される可能性のある設定が含まれています。一般的な例は、アプリケーションが Express を使用していることを示す X-Powered-By HTTP ヘッダーです。
脆弱なコードの例:
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
この設定では、すべての HTTP 応答に X-Powered-By: Express ヘッダーが含まれます。
問題:
軽減策:
攻撃者がサーバーのフィンガープリントを取得するのを困難にするには、このヘッダーを無効にします。
改善されたコード:
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
ヘルメットによる軽減策の強化:
より良いアプローチは、アプリのセキュリティを向上させるためにさまざまな HTTP ヘッダーを設定するヘルメット ミドルウェアを使用することです。
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
なぜヘルメットを使用するのですか?
構成と展開の管理は、アプリケーションのセキュリティの重要な側面です。設定ミスは、攻撃者にとって無防備なドアとなる可能性があります。
運用サーバー上で開発モードでアプリケーションを実行すると、詳細なエラー メッセージやスタック トレースが公開される可能性があります。
脆弱なコードの例:
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
このセットアップでは、詳細なエラー メッセージがクライアントに送信されます。
問題:
軽減策:
NODE_ENV を「実稼働」に設定し、実稼働環境で一般的なエラー メッセージを使用します。
改善されたコード:
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
ベストプラクティス:
JSON Web トークン (JWT) に署名するための単純な秘密キーなど、デフォルトの資格情報や弱い資格情報を使用することは、よくあるセキュリティ上の間違いです。
脆弱なコードの例:
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
問題:
軽減策:
強力で安全な秘密キーを使用し、安全に保管してください。
改善されたコード:
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
ベストプラクティス:
ID 管理は、ユーザー アカウントを保護し、不正アクセスを防止するために重要です。
脆弱なユーザー名を許可し、特定のエラー メッセージを提供すると、アカウント列挙攻撃につながる可能性があります。
脆弱なコードの例:
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
問題:
軽減策:
ユーザー名の検証を実装し、一般的なエラー メッセージを使用します。
改善されたコード:
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
説明:
認証メカニズムは、ユーザー ID を検証し、不正アクセスを防止するために不可欠です。
保護が欠如しているため、攻撃者は繰り返し試行することでパスワードや 2FA コードを推測できます。
脆弱なコードの例:
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
問題:
軽減策:
レート制限を実装し、2FA セキュリティを強化します。
改善されたコード:
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
追加措置:
説明:
認可 により、ユーザーは使用を許可されたリソースのみにアクセスできるようになり、不正なアクションが防止されます。
ユーザーはリクエスト内の識別子を操作することで、未承認のリソースにアクセスできます。
脆弱なコードの例:
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
問題:
軽減策:
アクセスを提供する前にリソースの所有権を検証します。
改善されたコード:
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
説明:
セッション管理は、ユーザーの状態を維持し、安全な対話を確保するために重要です。
有効期限のないトークンは、侵害された場合にセキュリティ上のリスクを引き起こします。
脆弱なコードの例:
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
問題:
軽減策:
トークンの有効期限を設定します。
改善されたコード:
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
説明:
トークンを localStorage に保存すると、クロスサイト スクリプティング (XSS) 攻撃にさらされます。
脆弱なコードの例:
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
問題:
軽減策:
HTTP のみの Cookie を使用してトークンを安全に保存します。
改善されたコード:
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
説明:
入力検証 は、ユーザーが提供したデータが安全かつ期待どおりであることを保証し、インジェクション攻撃を防ぎます。
検証せずにユーザー入力を受け入れて処理すると、脆弱性が発生する可能性があります。
脆弱なコードの例:
const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); // Weak secret key const SECRET_KEY = 'secret'; app.post('/login', (req, res) => { // Authenticate user (authentication logic not shown) const userId = req.body.userId; // Sign the JWT with a weak secret const token = jwt.sign({ userId }, SECRET_KEY); res.json({ token }); }); app.get('/protected', (req, res) => { const token = req.headers['authorization']; try { // Verify the token using the weak secret const decoded = jwt.verify(token, SECRET_KEY); res.send('Access granted to protected data'); } catch (err) { res.status(401).send('Unauthorized'); } }); app.listen(3000, () => { console.log('Server started on port 3000'); });
問題:
軽減策:
すべてのユーザー入力を検証し、サニタイズします。
改善されたコード:
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
説明:
適切なエラー処理により、機密情報の漏洩が回避され、ユーザー エクスペリエンスが向上します。
詳細なエラー メッセージにより、攻撃者にシステム内部の情報が明らかになる可能性があります。
脆弱なコードの例:
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
問題:
軽減策:
一般的なエラー メッセージを使用し、詳細なエラーを内部的に記録します。
改善されたコード:
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
説明:
暗号化は機密データを保護します。弱い暗号化手法を使用すると、セキュリティが損なわれます。
古いアルゴリズムでパスワードをハッシュするのは安全ではありません。
脆弱なコードの例:
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
問題:
軽減策:
パスワード用に設計された強力なハッシュ アルゴリズムを使用します。
改善されたコード:
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
説明:
シークレットをコードに直接保存すると、漏洩のリスクが高まります。
脆弱なコードの例:
const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); // Weak secret key const SECRET_KEY = 'secret'; app.post('/login', (req, res) => { // Authenticate user (authentication logic not shown) const userId = req.body.userId; // Sign the JWT with a weak secret const token = jwt.sign({ userId }, SECRET_KEY); res.json({ token }); }); app.get('/protected', (req, res) => { const token = req.headers['authorization']; try { // Verify the token using the weak secret const decoded = jwt.verify(token, SECRET_KEY); res.send('Access granted to protected data'); } catch (err) { res.status(401).send('Unauthorized'); } }); app.listen(3000, () => { console.log('Server started on port 3000'); });
問題:
軽減策:
シークレットを環境変数または安全な構成ファイルに保存します。
改善されたコード:
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
説明:
ビジネス ロジックの脆弱性は、アプリケーション フローが意図しない方法で操作される可能性がある場合に発生します。
無制限のデータ操作は、パフォーマンスの問題やデータ漏洩につながる可能性があります。
脆弱なコードの例:
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
問題:
軽減策:
ページネーションとアクセス制御を実装します。
改善されたコード:
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
説明:
クロスサイト スクリプティング (XSS) などの攻撃からユーザーを守るには、クライアント側の脆弱性から保護することが不可欠です。
クライアント側スクリプトでのユーザー入力の不適切な処理は、XSS 攻撃につながる可能性があります。
脆弱なコードの例:
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
問題:
軽減策:
xss ライブラリを使用して、レンダリング前にユーザー入力をサニタイズします。
改善されたコード:
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
説明:
ベストプラクティス:
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
データ漏洩や不正アクセスを防ぐには、API エンドポイントを保護することが重要です。
本番環境で GraphQL イントロスペクションを有効にしたままにすると、API スキーマが明らかになります。
脆弱なコードの例:
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
問題:
軽減策:
実稼働環境ではイントロスペクションを無効にします。
改善されたコード:
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
説明:
深くネストされたクエリや複雑なクエリは、サーバー リソースを使い果たす可能性があります。
脆弱なコードの例:
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
問題:
軽減策:
クエリの深さと複雑さを制限します。
改善されたコード:
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
説明:
Node.js アプリケーションの保護には、多層のアプローチが必要です。
これらのプラクティスを統合することで、アプリケーションのセキュリティを強化し、ユーザー データを保護し、信頼を維持できます。
注: このガイドでは、一般的な推奨事項を提供します。特定のセキュリティ上の懸念については、専門家にご相談ください。
以上がNode.js アプリケーションの保護: 包括的なガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。