UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

170 lines (138 loc) 4.94 kB
'use strict' const { LRUCache } = require('../../../../../vendor/dist/lru-cache') const { keepTrace } = require('../../priority_sampler') const { reportStackTrace, getCallsiteFrames, canReportStackTrace, STACK_TRACE_NAMESPACES } = require('../stack_trace') const { ASM } = require('../../standalone/product') const vulnerabilitiesFormatter = require('./vulnerabilities-formatter') const { IAST_ENABLED_TAG_KEY, IAST_JSON_TAG_KEY } = require('./tags') const { getOriginalPathAndLineFromSourceMap } = require('./taint-tracking/rewriter') const VULNERABILITIES_KEY = 'vulnerabilities' const VULNERABILITY_HASHES_MAX_SIZE = 1000 const VULNERABILITY_HASHES = new LRUCache({ max: VULNERABILITY_HASHES_MAX_SIZE }) const RESET_VULNERABILITY_CACHE_INTERVAL = 60 * 60 * 1000 // 1 hour let tracer let resetVulnerabilityCacheTimer let deduplicationEnabled = true let stackTraceEnabled = true let stackTraceMaxDepth let maxStackTraces function canAddVulnerability (vulnerability) { const hasRequiredFields = vulnerability?.evidence && vulnerability?.type && vulnerability?.location if (!hasRequiredFields) return false const isDuplicated = deduplicationEnabled && isDuplicatedVulnerability(vulnerability) return !isDuplicated } function addVulnerability (iastContext, vulnerability, callSiteFrames) { if (!canAddVulnerability(vulnerability)) return VULNERABILITY_HASHES.set(`${vulnerability.type}${vulnerability.hash}`, true) let span = iastContext?.rootSpan if (!span && tracer) { span = tracer.startSpan('vulnerability', { type: 'vulnerability', }) vulnerability.location.spanId = span.context().toSpanId() span.addTags({ [IAST_ENABLED_TAG_KEY]: 1, }) } if (!span) return keepTrace(span, ASM) if (stackTraceEnabled && canReportStackTrace(span, maxStackTraces, STACK_TRACE_NAMESPACES.IAST)) { const originalCallSiteList = callSiteFrames.map(callsite => replaceCallSiteFromSourceMap(callsite)) reportStackTrace( span, vulnerability.location.stackId, originalCallSiteList, STACK_TRACE_NAMESPACES.IAST ) } if (iastContext?.rootSpan) { iastContext[VULNERABILITIES_KEY] = iastContext[VULNERABILITIES_KEY] || [] iastContext[VULNERABILITIES_KEY].push(vulnerability) } else { sendVulnerabilities([vulnerability], span) span.finish() } } function isValidVulnerability (vulnerability) { return vulnerability && vulnerability.type && vulnerability.evidence && vulnerability.location && vulnerability.location.spanId } function sendVulnerabilities (vulnerabilities, span) { if (vulnerabilities?.length && span?.addTags) { const validatedVulnerabilities = vulnerabilities.filter(isValidVulnerability) const jsonToSend = vulnerabilitiesFormatter.toJson(validatedVulnerabilities) if (jsonToSend.vulnerabilities.length > 0) { const tags = { // TODO: Store this outside of the span and set the tag in the exporter. [IAST_JSON_TAG_KEY]: JSON.stringify(jsonToSend), } span.addTags(tags) } } return IAST_JSON_TAG_KEY } function clearCache () { // only for test purposes VULNERABILITY_HASHES.clear() } function startClearCacheTimer () { resetVulnerabilityCacheTimer = setInterval(clearCache, RESET_VULNERABILITY_CACHE_INTERVAL) resetVulnerabilityCacheTimer.unref?.() } function stopClearCacheTimer () { if (resetVulnerabilityCacheTimer) { clearInterval(resetVulnerabilityCacheTimer) resetVulnerabilityCacheTimer = null } } function isDuplicatedVulnerability (vulnerability) { return VULNERABILITY_HASHES.get(`${vulnerability.type}${vulnerability.hash}`) } function getVulnerabilityCallSiteFrames () { return getCallsiteFrames(stackTraceMaxDepth, getVulnerabilityCallSiteFrames) } function replaceCallSiteFromSourceMap (callsite) { if (callsite) { const { path, line, column } = getOriginalPathAndLineFromSourceMap(callsite) if (path) { callsite.file = path callsite.path = path } if (line) { callsite.line = line } // We send the column in the stack trace but not in the vulnerability location if (column) { callsite.column = column } } return callsite } function start (config, _tracer) { deduplicationEnabled = config.iast.deduplicationEnabled stackTraceEnabled = config.iast.stackTrace.enabled stackTraceMaxDepth = config.appsec.stackTrace.maxDepth maxStackTraces = config.appsec.stackTrace.maxStackTraces vulnerabilitiesFormatter.setRedactVulnerabilities( config.iast.redactionEnabled, config.iast.redactionNamePattern, config.iast.redactionValuePattern ) if (deduplicationEnabled) { startClearCacheTimer() } tracer = _tracer } function stop () { stopClearCacheTimer() } module.exports = { addVulnerability, sendVulnerabilities, getVulnerabilityCallSiteFrames, replaceCallSiteFromSourceMap, clearCache, start, stop, }