UNPKG

@hclsoftware/secagent

Version:

IAST agent

95 lines (81 loc) 3.64 kB
//IASTIGNORE /* * **************************************************** * Licensed Materials - Property of HCL. * (c) Copyright HCL Technologies Ltd. 2017, 2025. * Note to U.S. Government Users *Restricted Rights. * **************************************************** */ const {RequestRule, AdditionalInfoKey} = require('./RequestRule') const Vulnerability = require('../Vulnerability') const { ConfigInfo } = require('../ConfigFile/ConfigInfo') const SessionTracker = require('../SessionTracker') class Csrf extends RequestRule { constructor () { super(Vulnerability.CSRF, true) this.currentRequestInfo = null } isVulnerable (requestInfo, responseText, additionalInfo) { this.currentRequestInfo = requestInfo const isVulnerable = this.isCurrentRequestImportant(additionalInfo) && this.sessionCookieUsed(additionalInfo) && !this.isLoginRequest() && !this.currentRequestHasValidCsrfToken() && this.isSessionLoggedIn(responseText) if (isVulnerable) { additionalInfo[AdditionalInfoKey] = additionalInfo[AdditionalInfoKey].origConcat("; not a login request; no valid csrf token detected; session logged in") } return isVulnerable } isSessionLoggedIn (responseText) { return SessionTracker.responseTextMatchesInSessionPattern(responseText) } isCurrentRequestImportant (additionalInfo) { const isImportant = this.currentRequestInfo.method.origToUpperCase() === 'POST' || this.isUserConfigRequest(additionalInfo) if (isImportant) { additionalInfo[AdditionalInfoKey] = additionalInfo[AdditionalInfoKey].origConcat(`HTTP method: [${this.currentRequestInfo.method.origToUpperCase()}]`) } return isImportant } isUserConfigRequest (additionalInfo) { for (const userRequest of ConfigInfo.ConfigInfo.csrfRequests) { if (userRequest.equalsToActualRequest(this.currentRequestInfo)) { additionalInfo[AdditionalInfoKey] = additionalInfo[AdditionalInfoKey].origConcat("CSRF request specified in user config; ") return true } } return false } sessionCookieUsed(additionalInfo){ if (this.currentRequestInfo.session != null){ additionalInfo[AdditionalInfoKey] = additionalInfo[AdditionalInfoKey].origConcat("; active session detected") return true } for (const cookieName of this.currentRequestInfo.usedCookies){ if (SessionTracker.isSessionCookie(cookieName)){ additionalInfo[AdditionalInfoKey] = additionalInfo[AdditionalInfoKey].origConcat(`; session cookie used: [${cookieName}]`) return true } } return false } isLoginRequest(){ return SessionTracker.isLoginRequest(this.currentRequestInfo) } currentRequestHasValidCsrfToken () { return this.hasValidToken(this.currentRequestInfo.allParameters, this.currentRequestInfo.isUsedParameter) || this.hasValidToken(this.currentRequestInfo.headers, this.currentRequestInfo.isUsedHeader) } hasValidToken (container, isUsedToken) { for (const tokenCandidate in container) { if (this.isValidTokenName(tokenCandidate.toLowerCase())) { const csrfTokenValue = container[tokenCandidate] if (csrfTokenValue && isUsedToken.call(this.currentRequestInfo, tokenCandidate)) { return true } } } return false } isValidTokenName (parameterName) { return parameterName != null && (parameterName.origStringIncludes('csrf') || parameterName.origStringIncludes('xsrf')) && parameterName.origStringIncludes('token') } } module.exports = Csrf