Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: IAST support for Undici #130

Merged
merged 31 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1b63f32
Added instrumentation for undici. request, stream hooks added
sumitsuthar Nov 8, 2023
61f742b
implemented hook for fetch
sumitsuthar Nov 8, 2023
3e3ebb2
added comments
sumitsuthar Nov 8, 2023
d0ffb35
added intercepted args
sumitsuthar Nov 9, 2023
5badef2
Merge branch 'main' into undici_support
sumitsuthar Nov 10, 2023
8ea2cea
cleanup
sumitsuthar Nov 14, 2023
c05082b
merged main
sumitsuthar Nov 20, 2023
fe8c1d5
Merge branch 'main' into undici_support
sumitsuthar Nov 21, 2023
417edc8
Merge branch 'main' into undici_support
sumitsuthar Dec 1, 2023
67e75bd
Undici test (#138)
pratik-k2 Dec 6, 2023
ed0a456
Merge branch 'main' into undici_support
sumitsuthar Dec 11, 2023
bcc6bf2
Merge branch 'main' into undici_support
sumitsuthar Dec 11, 2023
eb63f15
Merge branch 'main' into undici_support
sumitsuthar Dec 14, 2023
a1d372b
Merge branch 'main' into undici_support
sumitsuthar Dec 15, 2023
9dd9b53
Merge branch 'main' into undici_support
sumitsuthar Dec 15, 2023
65c1b59
Merge branch 'main' into undici_support
sumitsuthar Jan 2, 2024
371a9d2
Merge branch 'main' into undici_support
sumitsuthar Jan 5, 2024
8c7a8e6
Merge branch 'main' into undici_support
sumitsuthar Jan 9, 2024
141381b
added error logs
sumitsuthar Jan 9, 2024
61184ad
removed check for data.path in request and stream
sumitsuthar Jan 9, 2024
150ab64
added default data.path as empty string
sumitsuthar Jan 9, 2024
8ac7950
removed data.path from completeURL
sumitsuthar Jan 9, 2024
e873d36
Merge branch 'main' into undici_support
sumitsuthar Jan 11, 2024
f8b02e3
Merge branch 'main' into undici_support
sumitsuthar Jan 18, 2024
e1ddad5
Merge branch 'main' into undici_support
sumitsuthar Jan 22, 2024
4ddb06d
Merge branch 'main' into undici_support
sumitsuthar Jan 23, 2024
dfb8c7b
updated hook for request and stream
sumitsuthar Jan 25, 2024
4654b9f
updated check for request
sumitsuthar Jan 25, 2024
8e5ddcb
logger added
sumitsuthar Jan 30, 2024
38ae824
Merge branch 'main' into undici_support
sumitsuthar Jan 30, 2024
fa55307
Merge branch 'main' into undici_support
sumitsuthar Feb 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions lib/instrumentation-security/hooks/undici/nr-undici.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2023 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: New Relic Pre-Release
*/

module.exports = initialize
const requestManager = require('../../core/request-manager');
const secUtils = require("../../core/sec-utils");
const API = require("../../../nr-security-api");
const lodash = require('lodash');
const securityMetaData = require('../../core/security-metadata');
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
const { NR_CSEC_FUZZ_REQUEST_ID, QUESTION_MARK, EMPTY_STRING, COLON, SLASH } = require('../../core/constants');
const NRCSECTRACINGDATA = 'NR-CSEC-TRACING-DATA';
const DOUBLE_SLASH = '//';
const logger = API.getLogger();
const url = require('url');


/**
* Entry point undici module instrumentation.
* @param {*} shim
* @param {*} mod
* @param {*} moduleName
*/
function initialize(shim, mod, moduleName) {
logger.info('Instrumenting ' + moduleName);
fetchHook(shim, mod, "fetch");
let util = shim.require('./lib/core/util');
parseOriginHook(shim, util, "parseOrigin")

}
/**
* Wrapper for util.parseOrigin
* @param {*} shim
* @param {*} mod
* @param {*} methodName
*/
function parseOriginHook(shim, mod, methodName) {
shim.wrap(mod, methodName, function ClientWrapper(shim, fn) {
logger.debug(`Instrumenting ${methodName}`);
if (!shim.isFunction(fn)) {
return fn
}
return function wrapper() {
const request = requestManager.getRequest(shim);
try {
if (typeof arguments[0] === 'string') {
let URLObject = new URL(arguments[0]);
const data = {};
data.headers = {};
data.path = URLObject.pathname ? URLObject.pathname : EMPTY_STRING;
data.protocol = URLObject.protocol ? URLObject.protocol : 'http:';
data.headers.host = URLObject.host ? URLObject.host : URLObject.hostname;
shim.interceptedArgs = data;
if (request) {
const traceObject = secUtils.getTraceObject(shim);
const secMetadata = securityMetaData.getSecurityMetaData(request, data, traceObject, secUtils.getExecutionId(), EVENT_TYPE.HTTP_REQUEST, EVENT_CATEGORY.HTTP)
this.secEvent = API.generateSecEvent(secMetadata);
API.sendEvent(this.secEvent);
}
}
} catch (error) {

}
const result = fn.apply(this, arguments);
if (result && request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
API.generateExitEvent(this.secEvent);
delete this.secEvent
}
return result;
}
})
}

/**
* Wrapper to hook undici.fetch()
* @param {*} shim
* @param {*} mod
* @param {*} methodName
*/
function fetchHook(shim, mod, methodName) {
shim.wrap(mod, methodName, function makeWrapper(shim, fn) {
logger.debug(`Instrumenting ${methodName}`);
if (!shim.isFunction(fn)) {
return fn
}
return function wrapper() {
const request = requestManager.getRequest(shim);
try {
const completeURL = arguments[0];
const parsedUrl = url.parse(completeURL);
const data = {};
data.headers = {};
data.method = arguments[0].method ? arguments[0].method : EMPTY_STRING;
data.path = parsedUrl.pathname ? parsedUrl.pathname : parsedUrl.path;
data.protocol = parsedUrl.protocol;
data.headers.host = parsedUrl.host ? parsedUrl.host : parsedUrl.hostname;
data.port = parsedUrl.port ? parsedUrl.port : parsedUrl.port;

shim.interceptedArgs = data;
if (request && !lodash.isEmpty(data.headers.host) && !lodash.isEmpty(data.path)) {
const appUUID = API.getSecAgent().applicationInfo.applicationUUID;
const traceObject = secUtils.getTraceObject(shim);
const secMetadata = securityMetaData.getSecurityMetaData(request, data, traceObject, secUtils.getExecutionId(), EVENT_TYPE.HTTP_REQUEST, EVENT_CATEGORY.HTTP)
this.secEvent = API.generateSecEvent(secMetadata);
API.sendEvent(this.secEvent);

let traceHeader = EMPTY_STRING;
if (request.headers['nr-csec-tracing-data']) {
traceHeader = request.headers['nr-csec-tracing-data'];
}

if (arguments[1] instanceof Object) {
if (arguments[1] && arguments[1].headers && request.headers) {
arguments[1].headers[NRCSECTRACINGDATA] = traceHeader + appUUID + '/' + this.secEvent.apiId + '/' + this.secEvent.id + ';';
} else {
arguments[1].headers = {};
arguments[1].headers[NRCSECTRACINGDATA] = traceHeader + appUUID + '/' + this.secEvent.apiId + '/' + this.secEvent.id + ';';
}
if (request && request.headers[NR_CSEC_FUZZ_REQUEST_ID] && arguments[1].headers) {
arguments[1].headers[NR_CSEC_FUZZ_REQUEST_ID] = request.headers[NR_CSEC_FUZZ_REQUEST_ID];
}
}
}
} catch (error) {
logger.debug("Error while extracting undici fetch args:", error);
}
const result = fn.apply(this, arguments);

if (result && request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
API.generateExitEvent(this.secEvent);
delete this.secEvent
}
return result;
}
})
}

9 changes: 9 additions & 0 deletions lib/instrumentation-security/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,15 @@ newrelic.instrumentWebframework({
}
})

newrelic.instrumentWebframework({
moduleName: 'undici',
isEsm: true,
onRequire: require('./hooks/undici/nr-undici'),
onError: function intrumentErrorHandler(err) {
logger.error(err.message, err.stack)
}
})




Expand Down
71 changes: 71 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"scripts": {
"test": "tap --test-regex='(\\/|^test\\/instrumentation-security\\/.*\\.test\\.js)$' --no-coverage",
"posttest": "rm -f newrelic_agent.log && rm -rf nr-security-home && rm -rf .nyc_output",
"third-party-updates": "oss third-party manifest && oss third-party notices && git add THIRD_PARTY_NOTICES.md third_party_manifest.json"
"third-party-updates": "oss third-party manifest && oss third-party notices && git add THIRD_PARTY_NOTICES.md third_party_manifest.json",
"undici": "tap test/instrumentation-security/nr-undici.test.js"
},
"keywords": [
"instrumentation",
Expand Down Expand Up @@ -84,7 +85,9 @@
"request": "^2.88.2",
"restify": "^11.1.0",
"sinon": "^15.0.0",
"stream": "^0.0.2",
"tap": "^16.3.2",
"undici": "^5.28.0",
"xmldom": "^0.6.0",
"xpath": "^0.0.32",
"xpath.js": "^1.1.0"
Expand Down
Loading
Loading