forked from Threagile/threagile
-
Notifications
You must be signed in to change notification settings - Fork 0
/
unnecessary-data-transfer-rule.go
142 lines (132 loc) · 6.43 KB
/
unnecessary-data-transfer-rule.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package unnecessary_data_transfer
import (
"sort"
"github.com/damianmcgrath/threagile/model"
)
func Category() model.RiskCategory {
return model.RiskCategory{
Id: "unnecessary-data-transfer",
Title: "Unnecessary Data Transfer",
Description: "When a technical asset sends or receives data assets, which it neither processes or stores this is " +
"an indicator for unnecessarily transferred data (or for an incomplete model). When the unnecessarily " +
"transferred data assets are sensitive, this poses an unnecessary risk of an increased attack surface.",
Impact: "If this risk is unmitigated, attackers might be able to target unnecessarily transferred data.",
ASVS: "V1 - Architecture, Design and Threat Modeling Requirements",
CheatSheet: "https://cheatsheetseries.owasp.org/cheatsheets/Attack_Surface_Analysis_Cheat_Sheet.html",
Action: "Attack Surface Reduction",
Mitigation: "Try to avoid sending or receiving sensitive data assets which are not required (i.e. neither " +
"processed or stored) by the involved technical asset.",
Check: "Are recommendations from the linked cheat sheet and referenced ASVS chapter applied?",
Function: model.Architecture,
STRIDE: model.ElevationOfPrivilege,
DetectionLogic: "In-scope technical assets sending or receiving sensitive data assets which are neither processed nor " +
"stored by the technical asset are flagged with this risk. The risk rating (low or medium) depends on the " +
"confidentiality, integrity, and availability rating of the technical asset. Monitoring data is exempted from this risk.",
RiskAssessment: "The risk assessment is depending on the confidentiality and integrity rating of the transferred data asset " +
"either " + model.LowSeverity.String() + " or " + model.MediumSeverity.String() + ".",
FalsePositives: "Technical assets missing the model entries of either processing or storing the mentioned data assets " +
"can be considered as false positives (incomplete models) after individual review. These should then be addressed by " +
"completing the model so that all necessary data assets are processed and/or stored by the technical asset involved.",
ModelFailurePossibleReason: true,
CWE: 1008,
}
}
func SupportedTags() []string {
return []string{}
}
func GenerateRisks() []model.Risk {
risks := make([]model.Risk, 0)
for _, id := range model.SortedTechnicalAssetIDs() {
technicalAsset := model.ParsedModelRoot.TechnicalAssets[id]
if technicalAsset.OutOfScope {
continue
}
// outgoing data flows
for _, outgoingDataFlow := range technicalAsset.CommunicationLinks {
targetAsset := model.ParsedModelRoot.TechnicalAssets[outgoingDataFlow.TargetId]
if targetAsset.Technology.IsUnnecessaryDataTolerated() {
continue
}
risks = checkRisksAgainstTechnicalAsset(risks, technicalAsset, outgoingDataFlow, false)
}
// incoming data flows
commLinks := model.IncomingTechnicalCommunicationLinksMappedByTargetId[technicalAsset.Id]
sort.Sort(model.ByTechnicalCommunicationLinkIdSort(commLinks))
for _, incomingDataFlow := range commLinks {
targetAsset := model.ParsedModelRoot.TechnicalAssets[incomingDataFlow.SourceId]
if targetAsset.Technology.IsUnnecessaryDataTolerated() {
continue
}
risks = checkRisksAgainstTechnicalAsset(risks, technicalAsset, incomingDataFlow, true)
}
}
return risks
}
func checkRisksAgainstTechnicalAsset(risks []model.Risk, technicalAsset model.TechnicalAsset,
dataFlow model.CommunicationLink, inverseDirection bool) []model.Risk {
for _, transferredDataAssetId := range dataFlow.DataAssetsSent {
if !technicalAsset.ProcessesOrStoresDataAsset(transferredDataAssetId) {
transferredDataAsset := model.ParsedModelRoot.DataAssets[transferredDataAssetId]
//fmt.Print("--->>> Checking "+technicalAsset.Id+": "+transferredDataAsset.Id+" sent via "+dataFlow.Id+"\n")
if transferredDataAsset.Confidentiality >= model.Confidential || transferredDataAsset.Integrity >= model.Critical {
commPartnerId := dataFlow.TargetId
if inverseDirection {
commPartnerId = dataFlow.SourceId
}
commPartnerAsset := model.ParsedModelRoot.TechnicalAssets[commPartnerId]
risk := createRisk(technicalAsset, transferredDataAsset, commPartnerAsset)
if isNewRisk(risks, risk) {
risks = append(risks, risk)
}
}
}
}
for _, transferredDataAssetId := range dataFlow.DataAssetsReceived {
if !technicalAsset.ProcessesOrStoresDataAsset(transferredDataAssetId) {
transferredDataAsset := model.ParsedModelRoot.DataAssets[transferredDataAssetId]
//fmt.Print("--->>> Checking "+technicalAsset.Id+": "+transferredDataAsset.Id+" received via "+dataFlow.Id+"\n")
if transferredDataAsset.Confidentiality >= model.Confidential || transferredDataAsset.Integrity >= model.Critical {
commPartnerId := dataFlow.TargetId
if inverseDirection {
commPartnerId = dataFlow.SourceId
}
commPartnerAsset := model.ParsedModelRoot.TechnicalAssets[commPartnerId]
risk := createRisk(technicalAsset, transferredDataAsset, commPartnerAsset)
if isNewRisk(risks, risk) {
risks = append(risks, risk)
}
}
}
}
return risks
}
func isNewRisk(risks []model.Risk, risk model.Risk) bool {
for _, check := range risks {
if check.SyntheticId == risk.SyntheticId {
return false
}
}
return true
}
func createRisk(technicalAsset model.TechnicalAsset, dataAssetTransferred model.DataAsset, commPartnerAsset model.TechnicalAsset) model.Risk {
moreRisky := dataAssetTransferred.Confidentiality == model.StrictlyConfidential || dataAssetTransferred.Integrity == model.MissionCritical
impact := model.LowImpact
if moreRisky {
impact = model.MediumImpact
}
title := "<b>Unnecessary Data Transfer</b> of <b>" + dataAssetTransferred.Title + "</b> data at <b>" + technicalAsset.Title + "</b> " +
"from/to <b>" + commPartnerAsset.Title + "</b>"
risk := model.Risk{
Category: Category(),
Severity: model.CalculateSeverity(model.Unlikely, impact),
ExploitationLikelihood: model.Unlikely,
ExploitationImpact: impact,
Title: title,
MostRelevantTechnicalAssetId: technicalAsset.Id,
MostRelevantDataAssetId: dataAssetTransferred.Id,
DataBreachProbability: model.Improbable,
DataBreachTechnicalAssetIDs: []string{technicalAsset.Id},
}
risk.SyntheticId = risk.Category.Id + "@" + dataAssetTransferred.Id + "@" + technicalAsset.Id + "@" + commPartnerAsset.Id
return risk
}