
Node Security Shield (NSS) は、オープンソースの Runtime Application Self-Protection (RASP) ツールであり、アプリケーションがアクセスできるリソースを開発者およびセキュリティエンジニアが宣言できるようにすることで、包括的な NodeJS セキュリティのギャップを埋めることを目的としています。
アプリケーションが任意のネットワーク呼び出しを行えるために悪用される可能性がある Log4Shell (CVE-2021-44228) 脆弱性に触発され、アプリケーションが許可する特権を宣言するメカニズムをアプリケーションに持たせる必要性を感じました。これにより、追加の制御を実装することで、そのような脆弱性の悪用をより困難にします。
これを実現するために、NSS (Node Security Shield) には Resource Access Policy (RAP) が備わっています。
Resource Access Policy は CSP (Content Security Policy) と似ています。
これにより、開発者/セキュリティエンジニアはアプリケーションがアクセスすべきリソースを宣言できます。そして Node Security Shield がそれを強制します。
npm install nodesecurityshield
// Node Security Shield の要求
let nodeSecurityShield = require('nodesecurityshield');
// 攻撃の監視および/またはブロックを有効化
nodeSecurityShield.enableAttackMonitoring("Unique-App-Id",resourceAccessPolicy ,callbackFunction);
const resourceAccessPolicy = {
"outBoundRequest" : {
"blockedDomains" : ["compromised.domdog.io"],
"allowedDomains" : []
},
"executedCommand": {
"allowedCommands": ["pwd" , "(node)[](https://github.com/domdogsec/nodesecurityshield/blob/HEAD/helper%5C/)[a-z|0-9]*(.js)"]
}
};
outBoundRequest: 外向けリクエストの許容される動作を定義します。
executedCommand: コマンド実行の許容される動作を定義します。
allowedCommands 配列は 文字列 を受け入れます。コマンドのパターンを許可するために正規表現を渡すことができます。executedCommand プロパティが定義されている場合、すべてのコマンド実行をブロックすることです。pwd コマンドの実行が許可され、helper 内の .js ファイルが node プロセスとして spawn されることが許可されます。.* の使用は避けてください。パイプ | の後に任意のコマンドが実行されることを許可してしまいます。var callbackFunction = function (violationEvent,violations,violationLimitPerMinReached) {
console.log(JSON.stringify(violationEvent,null, 4));
}
violationEvent - 発生した RAP 違反。CSP 違反として提示されます。
violations - RAP 違反のカウント。毎分ゼロにリセットされます。
violationLimitPerMinReached - RAP 違反カウントが 'maxViolationsPerMinute' (RAP のオプション) を超えた場合に true。
攻撃をブロックするには - エラーをスローします
throw new Error("Request Blocked. It violates declared Resource Access Policy.")
{
"csp-report": {
"document-uri": "https://Unique-App-Id",
"blocked-uri": "https://compromised.domdog.io:443",
"violated-directive": "connect-src",
"effective-directive": "connect-src",
"original-policy": "{\"outBoundRequest\":{\"blockedDomains\":[\"compromised.domdog.io\"],\"allowedDomains\":[]}}",
"disposition": "report",
"status-code": 200,
"script-sample": "",
"source-file": "Error\n at TLSSocket.obj.<computed> [as connect] (/mnt/c/Ironwasp/Product/NodeSecurityShield/lib/hook.js:20:25)\n at Object.connect (_tls_wrap.js:1606:13)\n at Agent.createConnection (https.js:126:22)\n at Agent.createSocket (_http_agent.js:273:26)\n at Agent.addRequest (_http_agent.js:232:10)\n at new ClientRequest (_http_client.js:302:16)\n at request (https.js:310:10)\n at Object.get (https.js:314:15)\n at /mnt/c/Ironwasp/RD/Node/SimpleVulnerableNode/routes/ssrf.js:19:19\n at Layer.handle [as handle_request] (/mnt/c/Ironwasp/RD/Node/SimpleVulnerableNode/node_modules/express/lib/router/layer.js:95:5)"
}
}
document-uri: NSS の初期化時に渡された Unique-App-Id が含まれます。blocked-uri: RAP に違反した外向けリクエストのドメイン。violated-directive: connect-src は 外向けリクエスト の同義語であり、同様に script-src は コマンド実行 の同義語です。original-policy: 違反された Resource Access Policy (RAP)。source-file: この違反が発生した場所のスタックトレース。const resourceAccessPolicy = {
"outBoundRequest" : {
"blockedDomains" : ["compromised.domdog.io"],
"allowedDomains" : []
},
"executedCommand": {
"allowedCommands": ["pwd" , "(node)[](https://github.com/domdogsec/nodesecurityshield/blob/HEAD/helper%5C/)[a-z|0-9]*(.js)"]
},
"reportUri": "https://ingest.sentry.io/api/6011856/security/?sentry_key=",
};
outBoundRequest: 外向けリクエストの許容される動作を定義します。
executedCommand: コマンド実行の許容される動作を定義します。
allowedCommands 配列は 文字列 を受け入れます。コマンドのパターンを許可するために正規表現を渡すことができます。executedCommand プロパティが定義されている場合、すべてのコマンド実行をブロックすることです。pwd コマンドの実行が許可され、helper 内の .js ファイルが node プロセスとして spawn されることが許可されます。.* の使用は避けてください。パイプ | の後に任意のコマンドが実行されることを許可してしまいます。Sentry ダッシュボードのスクリーンショット

const resourceAccessPolicy = {
"outBoundRequest" : {
"blockedDomains" : ["compromised.domdog.io"],
"allowedDomains" : ["domdog.io","*.domdog.io",
{
"domains": [
"domgo.at",
],
"modules": [
{
"file": "\/routes\/ssrf.js",
},
{
"file": "\/node_modules\/axios\/",
}
]
},
{
"domains": [
"cluster0-shard-00-00.lb9jm.mongodb.net",
"cluster0-shard-00-01.lb9jm.mongodb.net",
"cluster0-shard-00-02.lb9jm.mongodb.net"
],
"modules": [
{
"file": "\/node_modules\/mongodb\/"
}
]
}
]
},
"executedCommand": {
"allowedCommands": ["pwd" , "(node)[](https://github.com/domdogsec/nodesecurityshield/blob/HEAD/helper%5C/)[a-z|0-9]*(.js)"]
},
"reportUri": "https://endpoint-to-send-violations",
"maxViolationsPerMinute": 50
}
outBoundRequest: 外向けリクエストの許容される動作を定義します。
executedCommand: コマンド実行の許容される動作を定義します。
allowedCommands 配列は 文字列 を受け入れます。コマンドのパターンを許可するために正規表現を渡すことができます。executedCommand プロパティが定義されている場合、すべてのコマンド実行をブロックすることです。pwd コマンドの実行が許可され、helper 内の .js ファイルが node プロセスとして spawn されることが許可されます。.* の使用は避けてください。パイプ | の後に任意のコマンドが実行されることを許可してしまいます。reportUri : 違反を指定されたエンドポイントに送信します。違反は Content Security Policy 違反と似ているため、任意の CSP 監視ソリューションを使用できます。上記の RAP では Sentry エンドポイントを使用しました。reportUri: 違反を指定されたエンドポイントに送信します。違反は Content Security Policy 違反と似ており、任意の CSP 監視ソリューションを使用できます。上記の RAP では Sentry エンドポイントを使用しました。allowedDomain 配列は以下のプロパティを持つオブジェクトを受け入れます
domain: 指定されたファイルに対して許可されるドメインの配列。modules: ファイルパスを含むオブジェクトの配列。これらのファイルを介して指定されたドメインに行われる外向けリクエストのみが許可されます。maxViolationsPerMinute: reportUri に送信される違反の最大数。指定しない場合、デフォルト値 (100 件の違反) が使用されます。