From 40c0d864cfe2a6a0ee02ee1e0cec8c9bc7572ef1 Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Wed, 16 Oct 2024 18:41:41 +0530 Subject: [PATCH 01/12] handling to generate response event --- .../hooks/http/nr-http.js | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index 3c71a775..d8222d3b 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -22,6 +22,7 @@ const NRAgent = API.getNRAgent(); const securityMetaData = require('../../core/security-metadata'); const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants'); const hc = require('../../../nr-security-agent/lib/core/health-check'); +const LinkingMetaData = require('../../../nr-security-agent/lib/core/LinkingMetadata'); const NRCSECTRACINGDATA = 'NR-CSEC-TRACING-DATA'; const SELFTEST = 'self-test'; @@ -176,7 +177,7 @@ function parseFuzzheaders(requestData, transactionId) { if (additionalData.length >= 8) { let encryptedData = additionalData[6].trim(); let hashVerifier = additionalData[7].trim(); - + if (lodash.isEmpty(encryptedData) || lodash.isEmpty(hashVerifier)) { return; } @@ -465,10 +466,43 @@ function responseHook(resp, req, shim) { secEvent.httpResponse.contentType = response.getHeader(CONTENT_TYPE); API.sendEvent(secEvent); } + + if (request) { + generateTransactionEvent(request, response); + } + return fn.apply(this, arguments); } }) } + +/** + * Generate transactionEvent + */ +function generateTransactionEvent(request, response) { + let transactionEvent = {}; + let applicationInfo = API.getSecAgent().applicationInfo; + transactionEvent.jsonVersion = applicationInfo.jsonVersion; + transactionEvent.pid = applicationInfo.pid ? applicationInfo.pid : null; + transactionEvent.jsonName = 'sec_http_response'; + transactionEvent.eventType = transactionEvent.jsonName; + if (NRAgent) { + transactionEvent.linkingMetadata = LinkingMetaData.getLinkingMetadata(); + transactionEvent.traceId = transactionEvent.linkingMetadata['trace.id']; + } + transactionEvent.applicationUUID = applicationInfo.applicationUUID; + transactionEvent.policyVersion = applicationInfo.policyVersion; + transactionEvent.collectorVersion = applicationInfo.collectorVersion ? applicationInfo.collectorVersion : null; + transactionEvent.buildNumber = applicationInfo.buildNumber ? applicationInfo.buildNumber : null; + transactionEvent.timestamp = Date.now(); + transactionEvent.httpRequest = request; + transactionEvent.response = {}; + transactionEvent.response.responseBody = response.res.body; + transactionEvent.response.responseCode = response.statusCode; + transactionEvent.response.headers = response.getHeaders(); + transactionEvent.response.contentType = response.getHeader(CONTENT_TYPE); + logger.debug("Response event is:", JSON.stringify(transactionEvent)) +} /** * Utility to check unsupported content types * @param {*} conType From 63ad5c9d75b9bcd74880f4dd8550b5eac8b79fb4 Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Thu, 17 Oct 2024 10:00:01 +0530 Subject: [PATCH 02/12] updated response transaction event --- lib/instrumentation-security/hooks/http/nr-http.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index d8222d3b..6addbd56 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -487,6 +487,8 @@ function generateTransactionEvent(request, response) { transactionEvent.jsonName = 'sec_http_response'; transactionEvent.eventType = transactionEvent.jsonName; if (NRAgent) { + transactionEvent.appEntityGuid = NRAgent.config.entity_guid; + transactionEvent.appAccountId = NRAgent.config.account_id; transactionEvent.linkingMetadata = LinkingMetaData.getLinkingMetadata(); transactionEvent.traceId = transactionEvent.linkingMetadata['trace.id']; } @@ -496,11 +498,11 @@ function generateTransactionEvent(request, response) { transactionEvent.buildNumber = applicationInfo.buildNumber ? applicationInfo.buildNumber : null; transactionEvent.timestamp = Date.now(); transactionEvent.httpRequest = request; - transactionEvent.response = {}; - transactionEvent.response.responseBody = response.res.body; - transactionEvent.response.responseCode = response.statusCode; - transactionEvent.response.headers = response.getHeaders(); - transactionEvent.response.contentType = response.getHeader(CONTENT_TYPE); + transactionEvent.httpResponse = {}; + transactionEvent.httpResponse.body = response.res.body; + transactionEvent.httpResponse.statusCode = response.statusCode; + transactionEvent.httpResponse.headers = response.getHeaders(); + transactionEvent.httpResponse.contentType = response.getHeader(CONTENT_TYPE); logger.debug("Response event is:", JSON.stringify(transactionEvent)) } /** From 2433bcedb5f62a534c625feaf1a03a15943b2205 Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Mon, 21 Oct 2024 13:02:50 +0530 Subject: [PATCH 03/12] updated logic to enable response hook and processing of rxss on basis of flag --- .../hooks/http/nr-http.js | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index 6addbd56..118fe63a 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -293,9 +293,7 @@ function emitHook(shim, mod, moduleName) { const resp = arguments[2]; if (arguments[0] == 'request') { - if (NRAgent && NRAgent.config.security.detection.rxss.enabled) { - responseHook(resp, req, shim); - } + responseHook(resp, req, shim); shim.wrap(req, 'on', function makeOnWrapper(shim, fn) { if (!shim.isFunction(fn)) { @@ -448,25 +446,28 @@ function responseHook(resp, req, shim) { } responseBodyCompute(response, arguments); - - const construct = API.checkForReflectedXSS(request, response.res.body, response.getHeaders()); - const policy = API.getPolicy(); - const dynamicScanningFlag = policy.data ? (policy.data.vulnerabilityScan?.enabled && policy.data.vulnerabilityScan.iastScan.enabled) : false; - const type = response.getHeader(CONTENT_TYPE); - let isUnsupportedType = isUnsupportedContentType(type); - - if (request && (construct || dynamicScanningFlag) && !isUnsupportedType) { - const args = []; - args.push(construct); - args.push(response.res.body); - const traceObject = secUtils.getTraceObject(shim); - const secMetadata = securityMetaData.getSecurityMetaData(request, args, traceObject, secUtils.getExecutionId(), EVENT_TYPE.REFLECTED_XSS, EVENT_CATEGORY.REFLECTED_XSS) - const secEvent = API.generateSecEvent(secMetadata); - secEvent.httpResponse = {}; - secEvent.httpResponse.contentType = response.getHeader(CONTENT_TYPE); - API.sendEvent(secEvent); + if (NRAgent && NRAgent.config.security.detection.rxss.enabled) { + const construct = API.checkForReflectedXSS(request, response.res.body, response.getHeaders()); + const policy = API.getPolicy(); + const dynamicScanningFlag = policy.data ? (policy.data.vulnerabilityScan?.enabled && policy.data.vulnerabilityScan.iastScan.enabled) : false; + const type = response.getHeader(CONTENT_TYPE); + let isUnsupportedType = isUnsupportedContentType(type); + + if (request && (construct || dynamicScanningFlag) && !isUnsupportedType) { + const args = []; + args.push(construct); + args.push(response.res.body); + const traceObject = secUtils.getTraceObject(shim); + const secMetadata = securityMetaData.getSecurityMetaData(request, args, traceObject, secUtils.getExecutionId(), EVENT_TYPE.REFLECTED_XSS, EVENT_CATEGORY.REFLECTED_XSS) + const secEvent = API.generateSecEvent(secMetadata); + secEvent.httpResponse = {}; + secEvent.httpResponse.contentType = response.getHeader(CONTENT_TYPE); + API.sendEvent(secEvent); + } } + + if (request) { generateTransactionEvent(request, response); } From a1b1f2cbc0e295978b6a1ada71cfa7817c48153e Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Mon, 21 Oct 2024 13:09:00 +0530 Subject: [PATCH 04/12] minor fix --- lib/instrumentation-security/hooks/http/nr-http.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index 118fe63a..590804f0 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -468,7 +468,7 @@ function responseHook(resp, req, shim) { - if (request) { + if (request && API.getSecAgent()) { generateTransactionEvent(request, response); } From e4fe5caa8ce11e40d5265676bd3e743f83a402dc Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Mon, 28 Oct 2024 10:15:40 +0530 Subject: [PATCH 05/12] minor fix --- lib/instrumentation-security/hooks/http/nr-http.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index 590804f0..26d95298 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -468,7 +468,7 @@ function responseHook(resp, req, shim) { - if (request && API.getSecAgent()) { + if (request && API.getSecAgent() && NRAgent.config.security.scan_controllers && NRAgent.config.security.scan_controllers.report_http_response_body) { generateTransactionEvent(request, response); } From 7d3f31ce60faa7c655d98b31484559199dd42978 Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Mon, 28 Oct 2024 10:22:01 +0530 Subject: [PATCH 06/12] handling to generate reposne event only for vulnerable --- lib/instrumentation-security/hooks/http/nr-http.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index 26d95298..883b3042 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -468,8 +468,10 @@ function responseHook(resp, req, shim) { - if (request && API.getSecAgent() && NRAgent.config.security.scan_controllers && NRAgent.config.security.scan_controllers.report_http_response_body) { - generateTransactionEvent(request, response); + if (request && API.getSecAgent() && NRAgent.config.security.scan_controllers && NRAgent.config.security.scan_controllers.report_http_response_body) { + const fuzzHeader = request.headers[NR_CSEC_FUZZ_REQUEST_ID]; + if (fuzzHeader.includes('VULNERABLE')) + generateTransactionEvent(request, response); } return fn.apply(this, arguments); From 1493fbf6bf307c5c9d738d891876a901c0d561ef Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Mon, 28 Oct 2024 10:59:52 +0530 Subject: [PATCH 07/12] handling to truncate http response --- lib/instrumentation-security/hooks/http/nr-http.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index 883b3042..18f00ee7 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -502,7 +502,17 @@ function generateTransactionEvent(request, response) { transactionEvent.timestamp = Date.now(); transactionEvent.httpRequest = request; transactionEvent.httpResponse = {}; - transactionEvent.httpResponse.body = response.res.body; + let responseBody = response.res.body; + try { + const contentLength = Buffer.byteLength(responseBody, 'utf8'); + let bodyLimit = 500000; + if (contentLength && contentLength > bodyLimit) { + responseBody = truncateStringToBytes(responseBody, bodyLimit); + } + } catch (error) { + logger.error("Error while truncating response body", error); + } + transactionEvent.httpResponse.body = responseBody; transactionEvent.httpResponse.statusCode = response.statusCode; transactionEvent.httpResponse.headers = response.getHeaders(); transactionEvent.httpResponse.contentType = response.getHeader(CONTENT_TYPE); From 07ac9e365f4d523733d066045d3516f36f8c0aab Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Thu, 16 Jan 2025 13:58:36 +0530 Subject: [PATCH 08/12] minor fix --- lib/instrumentation-security/hooks/http/nr-http.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index 258ef351..64089f9c 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -476,7 +476,7 @@ function responseHook(resp, req, shim) { } - if (request && API.getSecAgent() && NRAgent.config.security.scan_controllers && NRAgent.config.security.scan_controllers.report_http_response_body) { + if (request && API && API.getSecAgent() && NRAgent.config.security.scan_controllers && NRAgent.config.security.scan_controllers.report_http_response_body) { const fuzzHeader = request.headers[NR_CSEC_FUZZ_REQUEST_ID]; if (fuzzHeader && fuzzHeader.includes('VULNERABLE')) generateTransactionEvent(request, response); From 0e8df87a828a19ae362a0801e1b4c775c4543e62 Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Thu, 16 Jan 2025 14:00:55 +0530 Subject: [PATCH 09/12] minor fix --- lib/nr-security-api/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nr-security-api/index.js b/lib/nr-security-api/index.js index fa6ef1e5..971a4358 100644 --- a/lib/nr-security-api/index.js +++ b/lib/nr-security-api/index.js @@ -44,7 +44,7 @@ function getNRAgent() { NRAgent.config.security.exclude_from_iast_scan.iast_detection_category.ssrf = false; NRAgent.config.security.exclude_from_iast_scan.iast_detection_category.rxss = false; } - if(!NRAgent.config.security.scan_controllers.report_http_response_body ){ + if(NRAgent && NRAgent.config && !NRAgent.config.security.scan_controllers.report_http_response_body ){ NRAgent.config.security.scan_controllers.report_http_response_body = true; } return NRAgent; From a82873ecf849492200286f54e569294071f56dac Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Thu, 16 Jan 2025 14:30:46 +0530 Subject: [PATCH 10/12] removed hardcoded report_http_response flag --- lib/nr-security-api/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/nr-security-api/index.js b/lib/nr-security-api/index.js index 971a4358..ad92c20e 100644 --- a/lib/nr-security-api/index.js +++ b/lib/nr-security-api/index.js @@ -44,9 +44,7 @@ function getNRAgent() { NRAgent.config.security.exclude_from_iast_scan.iast_detection_category.ssrf = false; NRAgent.config.security.exclude_from_iast_scan.iast_detection_category.rxss = false; } - if(NRAgent && NRAgent.config && !NRAgent.config.security.scan_controllers.report_http_response_body ){ - NRAgent.config.security.scan_controllers.report_http_response_body = true; - } + return NRAgent; } From ad05b1ad96f9d31fdebbd82f5fc8e20304865b71 Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Thu, 16 Jan 2025 16:24:40 +0530 Subject: [PATCH 11/12] handling to send http response event over ws --- lib/instrumentation-security/hooks/http/nr-http.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index 64089f9c..c556055b 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -526,6 +526,7 @@ function generateTransactionEvent(request, response) { transactionEvent.httpResponse.headers = response.getHeaders(); transactionEvent.httpResponse.contentType = response.getHeader(CONTENT_TYPE); logger.debug("Response event is:", JSON.stringify(transactionEvent)) + API.sendEvent(transactionEvent); } /** * Utility to check unsupported content types From f8aa4c167ce303972ee74d6107d99e7129e95da2 Mon Sep 17 00:00:00 2001 From: Sumit Suthar Date: Thu, 16 Jan 2025 18:11:33 +0530 Subject: [PATCH 12/12] handling to not compute body for rxss in case of report_http_response_body flag to false --- lib/instrumentation-security/hooks/http/nr-http.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/instrumentation-security/hooks/http/nr-http.js b/lib/instrumentation-security/hooks/http/nr-http.js index c556055b..6c1c28fc 100755 --- a/lib/instrumentation-security/hooks/http/nr-http.js +++ b/lib/instrumentation-security/hooks/http/nr-http.js @@ -455,7 +455,7 @@ function responseHook(resp, req, shim) { } responseBodyCompute(response, arguments); - if (NRAgent && NRAgent.config.security.detection.rxss.enabled) { + if (NRAgent && NRAgent.config.security.detection.rxss.enabled && NRAgent.config.security.scan_controllers.report_http_response_body) { const construct = API.checkForReflectedXSS(request, response.res.body, response.getHeaders()); const policy = API.getPolicy(); const dynamicScanningFlag = policy.data ? (policy.data.vulnerabilityScan?.enabled && policy.data.vulnerabilityScan.iastScan.enabled) : false; @@ -584,6 +584,9 @@ function isUnsupportedContentType(conType) { } function responseBodyCompute(response, args) { + if(NRAgent && !NRAgent.config.security.scan_controllers.report_http_response_body){ + return; + } let encoding = UTF8; const type = response.getHeader(CONTENT_TYPE); let isUnsupportedType = isUnsupportedContentType(type);