-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathCleartextStorageDatabase.ql
More file actions
107 lines (95 loc) · 3.53 KB
/
CleartextStorageDatabase.ql
File metadata and controls
107 lines (95 loc) · 3.53 KB
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
/**
* @name Cleartext storage of sensitive information in a local database
* @description Storing sensitive information in a non-encrypted
* database can expose it to an attacker.
* @kind path-problem
* @problem.severity warning
* @security-severity 7.5
* @precision medium
* @id swift/cleartext-storage-database
* @tags security
* external/cwe/cwe-312
*/
import swift
import codeql.swift.security.SensitiveExprs
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import DataFlow::PathGraph
/**
* A `DataFlow::Node` that is something stored in a local database.
*/
abstract class Stored extends DataFlow::Node { }
/**
* A `DataFlow::Node` that is an expression stored with the Core Data library.
*/
class CoreDataStore extends Stored {
CoreDataStore() {
// values written into Core Data objects are a sink
exists(MethodDecl f, CallExpr call |
f.hasQualifiedName("NSManagedObject", ["setValue(_:forKey:)", "setPrimitiveValue(_:forKey:)"]) and
call.getStaticTarget() = f and
call.getArgument(0).getExpr() = this.asExpr()
)
}
}
/**
* A `DataFlow::Node` that is an expression stored with the Realm database
* library.
*/
class RealmStore extends Stored instanceof DataFlow::PostUpdateNode {
RealmStore() {
// any write into a class derived from `RealmSwiftObject` is a sink. For
// example in `realmObj.data = sensitive` the post-update node corresponding
// with `realmObj.data` is a sink.
exists(ClassOrStructDecl cd, Expr e |
cd.getABaseTypeDecl*().getName() = "RealmSwiftObject" and
this.getPreUpdateNode().asExpr() = e and
e.getFullyConverted().getType() = cd.getType() and
not e.(DeclRefExpr).getDecl() instanceof SelfParamDecl
)
}
}
/**
* A taint configuration from sensitive information to expressions that are
* transmitted over a network.
*/
class CleartextStorageConfig extends TaintTracking::Configuration {
CleartextStorageConfig() { this = "CleartextStorageConfig" }
override predicate isSource(DataFlow::Node node) { node.asExpr() instanceof SensitiveExpr }
override predicate isSink(DataFlow::Node node) { node instanceof Stored }
override predicate isSanitizerIn(DataFlow::Node node) {
// make sources barriers so that we only report the closest instance
isSource(node)
}
override predicate isSanitizer(DataFlow::Node node) {
// encryption barrier
node.asExpr() instanceof EncryptedExpr
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
// flow out from fields of a `RealmSwiftObject` at the sink, for example in
// `realmObj.data = sensitive`.
isSink(node) and
exists(ClassOrStructDecl cd |
c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cd.getAMember() and
cd.getABaseTypeDecl*().getName() = "RealmSwiftObject"
)
or
// any default implicit reads
super.allowImplicitRead(node, c)
}
}
/**
* Gets a prettier node to use in the results.
*/
DataFlow::Node cleanupNode(DataFlow::Node n) {
result = n.(DataFlow::PostUpdateNode).getPreUpdateNode()
or
not n instanceof DataFlow::PostUpdateNode and
result = n
}
from CleartextStorageConfig config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
where config.hasFlowPath(sourceNode, sinkNode)
select cleanupNode(sinkNode.getNode()), sourceNode, sinkNode,
"This operation stores '" + sinkNode.getNode().toString() +
"' in a database. It may contain unencrypted sensitive data from $@.", sourceNode,
sourceNode.getNode().toString()