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

Added implementation to send http response event #74

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 6 additions & 6 deletions internal/security_utils/global_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@

package security_utils

import "net/http"

const MaxReadBodyLen = 300000

type Info_req struct {
ResponseBody string
ResponseHeader http.Header
ResponseContentType string
GrpcBody []interface{}
ReqTraceData string
RequestIdentifier NrRequestIdentifier
Request RequestInfo
Response ResponseInfo
VulnerabilityDetails VulnerabilityDetails
ReflectedMetaData ReflectedMetaData
ParentID string
Expand All @@ -30,7 +26,11 @@ type ReflectedMetaData struct {
}

type ResponseInfo struct {
ContentType string `json:"contentType"`
ContentType string `json:"contentType"`
StatusCode int `json:"statusCode"`
Headers map[string]string `json:"headers"`
Body string `json:"body"`
HeadersMap map[string][]string `json:"-"`
}

type RequestInfo struct {
Expand Down
2 changes: 1 addition & 1 deletion internal/security_utils/xss_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func decodeRequestData(rq *Info_req) []string {

func decodeResponseData(rq *Info_req) []string {
var processedData []string
decodedBodyValue := processURLEncodedDataForXSS(rq.ResponseBody)
decodedBodyValue := processURLEncodedDataForXSS(rq.Response.Body)
processedData = append(processedData, decodedBodyValue...)
for _, st := range decodedBodyValue {
newprocessedBody := safeDecode(st)
Expand Down
6 changes: 6 additions & 0 deletions security_config/global_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ func (info *Info_struct) ScanScheduleSchedule() string {
return info.security.ScanSchedule.Schedule
}

func (info *Info_struct) ReportHttpResponseBody() bool {
info.securityMutex.Lock()
defer info.securityMutex.Unlock()
return info.security.ScanControllers.ReportHttpResponseBody
}

func (info *Info_struct) SecurityHomePath() string {
return info.security.SecurityHomePath
}
Expand Down
1 change: 1 addition & 0 deletions security_config/limits.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package security_config
const (
MaxStackTraceFrames = 100
ValidatorDefaultEndpoint = "wss://csec.nr-data.net"
HttpResponseBodyLimit = 500 * 1000 //500kb
)
3 changes: 2 additions & 1 deletion security_config/secure_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ type Security struct {
AllowIastSampleCollection bool `yaml:"always_sample_traces"`
} `yaml:"scan_schedule"`
ScanControllers struct {
IastScanRequestRateLimit int `yaml:"iast_scan_request_rate_limit"`
IastScanRequestRateLimit int `yaml:"iast_scan_request_rate_limit"`
ReportHttpResponseBody bool `yaml:"report_http_response_body: true"`
} `yaml:"scan_controllers"`
}

Expand Down
21 changes: 20 additions & 1 deletion security_event_generation/event_generation.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ func SendVulnerableEvent(req *secUtils.Info_req, category, eventCategory string,
tmp_event.VulnerabilityDetails = vulnerabilityDetails
tmp_event.ApplicationIdentifiers = getApplicationIdentifiers("Event")
tmp_event.EventGenerationTime = strconv.FormatInt(time.Now().Unix()*1000, 10)
tmp_event.HTTPResponse = secUtils.ResponseInfo{ContentType: req.ResponseContentType}
tmp_event.HTTPResponse = req.Response
tmp_event.MetaData.AppServerInfo.ApplicationDirectory = secConfig.GlobalInfo.EnvironmentInfo.Wd
tmp_event.MetaData.AppServerInfo.ServerBaseDirectory = secConfig.GlobalInfo.EnvironmentInfo.Wd
tmp_event.MetaData.SkipScanParameters = secConfig.GlobalInfo.SkipIastScanParameters()
Expand Down Expand Up @@ -395,6 +395,25 @@ func SendVulnerableEvent(req *secUtils.Info_req, category, eventCategory string,

}

func SendResponseEvent(req *secUtils.Info_req) {

if req != nil && secUtils.CaseInsensitiveEquals(req.RequestIdentifier.NextStage, "VULNERABLE") {

var tmp_event SecHttpResponse
tmp_event.ApplicationIdentifiers = getApplicationIdentifiers("sec-http-response")
tmp_event.HTTPRequest = nil
tmp_event.HTTPResponse = req.Response
tmp_event.TraceId = req.TraceId
tmp_event.IsIASTRequest = true
tmp_event.LinkingMetadata = copyMap(secConfig.GlobalInfo.MetaData.GetLinkingMetadata())
tmp_event.LinkingMetadata["trace.id"] = req.TraceId
_, err := sendEvent(tmp_event, "", "sec-http-response")
if err != nil {
logger.Errorln(err)
}
}
}

func SendExitEvent(eventTracker *secUtils.EventTracker, requestIdentifier string) {

var tmp_event Exitevent
Expand Down
8 changes: 8 additions & 0 deletions security_event_generation/event_generation_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ type ApplicationIdentifiers struct {
LinkingMetadata map[string]string `json:"linkingMetadata"`
}

type SecHttpResponse struct {
ApplicationIdentifiers
TraceId string `json:"traceId"`
HTTPResponse secUtils.ResponseInfo `json:"httpResponse"`
HTTPRequest interface{} `json:"httpRequest"`
IsIASTRequest bool `json:"isIASTRequest"`
}

type FuzzFailBean struct {
ApplicationIdentifiers
FuzzHeader string `json:"fuzzHeader"`
Expand Down
38 changes: 24 additions & 14 deletions security_intercept/intercept.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,26 +328,35 @@ func TraceIncommingRequest(url, host string, hdrMap map[string][]string, method
infoReq.Request.URI = getRequestUri(url)
infoReq.TraceId = traceId

if reqtype == "gRPC" {
if reqtype == "gRPC" {
infoReq.Request.IsGRPC = true
}

secConfig.Secure.AssociateInboundRequest(infoReq)
}

func associateResponseBody(body string) {
r := secConfig.Secure.GetRequest()
if r != nil {
r.ResponseBody = r.ResponseBody + body
secConfig.Secure.CalculateOutboundApiId()
if secConfig.GlobalInfo.ReportHttpResponseBody() {
r := secConfig.Secure.GetRequest()
if r != nil {
if l := len(r.Response.Body); len(body) <= secConfig.HttpResponseBodyLimit-l {
r.Response.Body = r.Response.Body + body
} else if secConfig.HttpResponseBodyLimit-l > 1 {
end := secConfig.HttpResponseBodyLimit - l
r.Response.Body = r.Response.Body + body[:end-1]
}
secConfig.Secure.CalculateOutboundApiId()
}
}

}

func associateResponseHeader(header http.Header) {
r := secConfig.Secure.GetRequest()
if r != nil {
r.ResponseHeader = header
r.ResponseContentType = header.Get("content-type")
r.Response.Headers = ToOneValueMap(header)
r.Response.HeadersMap = header
r.Response.ContentType = header.Get("content-type")
}
}

Expand Down Expand Up @@ -452,8 +461,9 @@ func traceResponseOperations() {

r := secConfig.Secure.GetRequest()
if r != nil {
checkSecureCookies(r.ResponseHeader)
checkSecureCookies(r.Response.HeadersMap)
xssCheck(r)
eventGeneration.SendResponseEvent(r)
}
}

Expand Down Expand Up @@ -484,24 +494,24 @@ func checkSecureCookies(responseHeader http.Header) {
}

func xssCheck(r *secUtils.Info_req) {
if !IsRxssDisabled() && r.ResponseBody != "" {
if !IsRxssDisabled() && r.Response.Body != "" {

contentType := r.ResponseContentType
contentType := r.Response.ContentType
if !secUtils.IsContentTypeSupported(contentType) {
SendLogMessage(SKIP_RXSS_EVENT+contentType, "XssCheck", "SEVERE")
logger.Debugln(SKIP_RXSS_EVENT, contentType)
return
}

// Double check befor rxss event validation becouse in some case we don't have contentType in response header.
cType := http.DetectContentType([]byte(r.ResponseBody))
cType := http.DetectContentType([]byte(r.Response.Body))
if !secUtils.IsContentTypeSupported(cType) {
SendLogMessage(SKIP_RXSS_EVENT+cType, "XssCheck", "SEVERE")
logger.Debugln(SKIP_RXSS_EVENT, cType)
return
}
if r.ResponseContentType == "" {
r.ResponseContentType = cType
if r.Response.ContentType == "" {
r.Response.ContentType = cType
}

out := secUtils.CheckForReflectedXSS(r)
Expand All @@ -512,7 +522,7 @@ func xssCheck(r *secUtils.Info_req) {
} else {
var arg []string
arg = append(arg, out)
arg = append(arg, r.ResponseBody)
arg = append(arg, r.Response.Body)
secConfig.Secure.SendEvent("REFLECTED_XSS", "REFLECTED_XSS", arg)
}
}
Expand Down
Loading