diff --git a/pkg/security/risks/builtin/missing_authentication_rule.go b/pkg/security/risks/builtin/missing_authentication_rule.go index c0be1da9..b66d3006 100644 --- a/pkg/security/risks/builtin/missing_authentication_rule.go +++ b/pkg/security/risks/builtin/missing_authentication_rule.go @@ -47,36 +47,39 @@ func (r *MissingAuthenticationRule) GenerateRisks(input *types.Model) ([]*types. continue } - if technicalAsset.HighestProcessedConfidentiality(input) >= types.Confidential || - technicalAsset.HighestProcessedIntegrity(input) >= types.Critical || - technicalAsset.HighestProcessedAvailability(input) >= types.Critical || - technicalAsset.MultiTenant { - // check each incoming data flow - commLinks := input.IncomingTechnicalCommunicationLinksMappedByTargetId[technicalAsset.Id] - for _, commLink := range commLinks { - caller := input.TechnicalAssets[commLink.SourceId] - if caller.Technologies.GetAttribute(types.IsUnprotectedCommunicationsTolerated) || caller.Type == types.Datastore { - continue - } - highRisk := commLink.HighestConfidentiality(input) == types.StrictlyConfidential || - commLink.HighestIntegrity(input) == types.MissionCritical - lowRisk := commLink.HighestConfidentiality(input) <= types.Internal && - commLink.HighestIntegrity(input) == types.Operational - impact := types.MediumImpact - if highRisk { - impact = types.HighImpact - } else if lowRisk { - impact = types.LowImpact - } - if commLink.Authentication == types.NoneAuthentication && !commLink.Protocol.IsProcessLocal() { - risks = append(risks, r.createRisk(input, technicalAsset, commLink, commLink, "", impact, types.Likely, false, r.Category())) - } + if technicalAsset.HighestProcessedConfidentiality(input) < types.Confidential && + technicalAsset.HighestProcessedIntegrity(input) < types.Critical && + technicalAsset.HighestProcessedAvailability(input) < types.Critical && + !technicalAsset.MultiTenant { + continue + } + + // check each incoming data flow + commLinks := input.IncomingTechnicalCommunicationLinksMappedByTargetId[technicalAsset.Id] + for _, commLink := range commLinks { + caller := input.TechnicalAssets[commLink.SourceId] + if caller.Technologies.GetAttribute(types.IsUnprotectedCommunicationsTolerated) || caller.Type == types.Datastore { + continue + } + impact := r.calculateImpact(commLink, input) + if commLink.Authentication == types.NoneAuthentication && !commLink.Protocol.IsProcessLocal() { + risks = append(risks, r.createRisk(input, technicalAsset, commLink, commLink, "", impact, types.Likely, false, r.Category())) } } } return risks, nil } +func (r *MissingAuthenticationRule) calculateImpact(commLink *types.CommunicationLink, input *types.Model) types.RiskExploitationImpact { + if commLink.HighestConfidentiality(input) == types.StrictlyConfidential || commLink.HighestIntegrity(input) == types.MissionCritical { + return types.HighImpact + } + if commLink.HighestConfidentiality(input) <= types.Internal && commLink.HighestIntegrity(input) == types.Operational { + return types.LowImpact + } + return types.MediumImpact +} + func (r *MissingAuthenticationRule) createRisk(input *types.Model, technicalAsset *types.TechnicalAsset, incomingAccess, incomingAccessOrigin *types.CommunicationLink, hopBetween string, impact types.RiskExploitationImpact, likelihood types.RiskExploitationLikelihood, twoFactor bool, category *types.RiskCategory) *types.Risk { factorString := "" diff --git a/pkg/security/risks/builtin/missing_authentication_rule_test.go b/pkg/security/risks/builtin/missing_authentication_rule_test.go index b2f08544..e0b0bfba 100644 --- a/pkg/security/risks/builtin/missing_authentication_rule_test.go +++ b/pkg/security/risks/builtin/missing_authentication_rule_test.go @@ -324,3 +324,43 @@ func TestMissingAuthenticationRuleGenerateRisksOperationalIntegrityRisksCreatedW assert.Equal(t, "Missing Authentication covering communication link User Access via Browser from User Interface to Test Technical Asset", risks[0].Title) assert.Equal(t, types.LowImpact, risks[0].ExploitationImpact) } + +func TestMissingAuthenticationRuleGenerateRisksProcessingConfidentialDataRisksCreated(t *testing.T) { + rule := NewMissingAuthenticationRule() + + risks, err := rule.GenerateRisks(&types.Model{ + TechnicalAssets: map[string]*types.TechnicalAsset{ + "ta1": { + Id: "ta1", + Title: "Test Technical Asset", + DataAssetsProcessed: []string{"confidential"}, + }, + "ta2": { + Id: "ta2", + Title: "User Interface", + }, + }, + IncomingTechnicalCommunicationLinksMappedByTargetId: map[string][]*types.CommunicationLink{ + "ta1": { + { + Title: "User Access via Browser", + SourceId: "ta2", + Authentication: types.NoneAuthentication, + Protocol: types.HTTPS, + }, + }, + }, + DataAssets: map[string]*types.DataAsset{ + "confidential": { + Id: "confidential", + Title: "Confidential Data", + Confidentiality: types.Confidential, + }, + }, + }) + + assert.Nil(t, err) + assert.Len(t, risks, 1) + assert.Equal(t, "Missing Authentication covering communication link User Access via Browser from User Interface to Test Technical Asset", risks[0].Title) + assert.Equal(t, types.MediumImpact, risks[0].ExploitationImpact) +}