Skip to content

Commit 794a86a

Browse files
committed
Python: Add SensitiveDataSource
1 parent 56c4097 commit 794a86a

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Provides an extension point for for modeling sensitive data, such as secrets, certificates, or passwords.
3+
* Sensitive data is can be interesting to use as data-flow sources in security queries.
4+
*/
5+
6+
private import python
7+
private import semmle.python.dataflow.new.DataFlow
8+
// Need to import since frameworks can extend `RemoteFlowSource::Range`
9+
private import semmle.python.Frameworks
10+
private import semmle.python.Concepts
11+
private import semmle.python.security.SensitiveData as OldSensitiveData
12+
13+
/**
14+
* A data flow source of sensitive data, such as secrets, certificates, or passwords.
15+
*
16+
* Extend this class to refine existing API models. If you want to model new APIs,
17+
* extend `SensitiveDataSource::Range` instead.
18+
*/
19+
class SensitiveDataSource extends DataFlow::Node {
20+
SensitiveDataSource::Range range;
21+
22+
SensitiveDataSource() { this = range }
23+
24+
/**
25+
* INTERNAL: Do not use.
26+
*
27+
* This will be rewritten to have better types soon, and therefore should only be used internally until then.
28+
*
29+
* Gets the classification of the sensitive data.
30+
*/
31+
string getClassification() { result = range.getClassification() }
32+
}
33+
34+
/** Provides a class for modeling new sources of sensitive data, such as secrets, certificates, or passwords. */
35+
module SensitiveDataSource {
36+
/**
37+
* A data flow source of sensitive data, such as secrets, certificates, or passwords.
38+
*
39+
* Extend this class to model new APIs. If you want to refine existing API models,
40+
* extend `SensitiveDataSource` instead.
41+
*/
42+
abstract class Range extends DataFlow::Node {
43+
/**
44+
* INTERNAL: Do not use.
45+
*
46+
* This will be rewritten to have better types soon, and therefore should only be used internally until then.
47+
*
48+
* Gets the classification of the sensitive data.
49+
*/
50+
abstract string getClassification();
51+
}
52+
}
53+
54+
private class PortOfOldModeling extends SensitiveDataSource::Range {
55+
OldSensitiveData::SensitiveData::Source oldSensitiveSource;
56+
57+
PortOfOldModeling() { this.asCfgNode() = oldSensitiveSource }
58+
59+
override string getClassification() {
60+
exists(OldSensitiveData::SensitiveData classification |
61+
oldSensitiveSource.isSourceOf(classification)
62+
|
63+
classification = "sensitive.data." + result
64+
)
65+
}
66+
}

python/ql/test/experimental/dataflow/sensitive-data/TestSensitiveDataSources.expected

Whitespace-only changes.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import python
2+
import semmle.python.dataflow.new.DataFlow
3+
import TestUtilities.InlineExpectationsTest
4+
import semmle.python.dataflow.new.SensitiveDataSources
5+
6+
class SensitiveDataSourcesTest extends InlineExpectationsTest {
7+
SensitiveDataSourcesTest() { this = "SensitiveDataSourcesTest" }
8+
9+
override string getARelevantTag() { result = "SensitiveDataSource" }
10+
11+
override predicate hasActualResult(Location location, string element, string tag, string value) {
12+
exists(location.getFile().getRelativePath()) and
13+
exists(SensitiveDataSource source |
14+
location = source.getLocation() and
15+
element = source.toString() and
16+
value = source.getClassification() and
17+
tag = "SensitiveDataSource"
18+
)
19+
}
20+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
from not_found import get_passwd, account_id
3+
4+
def get_password():
5+
pass
6+
7+
def get_secret():
8+
pass
9+
10+
def fetch_certificate():
11+
pass
12+
13+
def encrypt_password(pwd):
14+
pass
15+
16+
get_password() # $ SensitiveDataSource=password
17+
get_passwd() # $ SensitiveDataSource=password
18+
get_secret() # $ SensitiveDataSource=secret
19+
fetch_certificate() # $ SensitiveDataSource=certificate
20+
account_id() # $ SensitiveDataSource=id
21+
safe_to_store = encrypt_password(pwd)

0 commit comments

Comments
 (0)