Merge pull request #16570 from geoffw0/swiftssn

Swift: Use shared library for sensitive private information heuristics
This commit is contained in:
Geoffrey White
2024-07-19 16:06:47 +01:00
committed by GitHub
5 changed files with 103 additions and 27 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Additional heuristics for sensitive private information have been added to the `SensitiveExprs.qll` library, improving coverage for credit card and social security numbers. This may result in additional results for queries that use sensitive data such as `swift/cleartext-transmission`.

View File

@@ -64,33 +64,10 @@ class SensitivePrivateInfo extends SensitiveDataType, TPrivateInfo {
override string toString() { result = "private information" }
override string getRegexp() {
// we've had good results for the e-mail heuristic in Swift, which isn't part of the default regex. Add it in.
result =
"(?is).*(" +
// Inspired by the list on https://cwe.mitre.org/data/definitions/359.html
// Government identifiers, such as Social Security Numbers
"social.?security|employer.?identification|national.?insurance|resident.?id|" +
"passport.?(num|no)|" +
// Contact information, such as home addresses
"post.?code|zip.?code|home.?addr|" +
// and telephone numbers
"(mob(ile)?|home).?(num|no|tel|phone)|(tel|fax|phone).?(num|no)|telephone|" +
"emergency.?contact|" +
// Geographic location - where the user is (or was)
"l(atitude|ongitude)|nationality|" +
// Financial data - such as credit card numbers, salary, bank accounts, and debts
"(credit|debit|bank|visa).?(card|num|no|acc(ou?)nt)|acc(ou)?nt.?(no|num|credit)|" +
"salary|billing|credit.?(rating|score)|" +
// Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc.
"e(mail|_mail)|" +
// Health - medical conditions, insurance status, prescription records
"birth.?da(te|y)|da(te|y).?(of.?)?birth|" +
"medical|(health|care).?plan|healthkit|appointment|prescription|" +
"blood.?(type|alcohol|glucose|pressure)|heart.?(rate|rhythm)|body.?(mass|fat)|" +
"menstrua|pregnan|insulin|inhaler|" +
// Relationships - work and family
"employ(er|ee)|spouse|maiden.?name" +
// ---
").*"
HeuristicNames::maybeSensitiveRegexp(SensitiveDataClassification::private())
.replaceAll(".*(", ".*(e(mail|_mail)|")
}
}

View File

@@ -69,6 +69,7 @@ edges
| SQLite.swift:197:17:197:49 | [...] [Collection element] | SQLite.swift:197:16:197:50 | [...] [Collection element, Collection element] | provenance | |
| SQLite.swift:197:18:197:32 | ... <-(_:_:) ... | SQLite.swift:197:17:197:49 | [...] [Collection element] | provenance | |
| SQLite.swift:197:32:197:32 | mobilePhoneNumber | SQLite.swift:197:18:197:32 | ... <-(_:_:) ... | provenance | |
| file://:0:0:0:0 | [post] self [data, Collection element] | testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | provenance | |
| file://:0:0:0:0 | [post] self [data] | testRealm2.swift:13:6:13:6 | self [Return] [data] | provenance | |
| file://:0:0:0:0 | [post] self [data] | testRealm.swift:27:6:27:6 | self [Return] [data] | provenance | |
| file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] | testCoreData2.swift:23:13:23:13 | self [Return] [notStoredBankAccountNumber] | provenance | |
@@ -82,6 +83,7 @@ edges
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] | provenance | |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [password] | provenance | |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [value] | provenance | |
| file://:0:0:0:0 | value [Collection element] | file://:0:0:0:0 | [post] self [data, Collection element] | provenance | |
| sqlite3_c_api.swift:42:69:42:69 | medicalNotes | sqlite3_c_api.swift:46:27:46:27 | insertQuery | provenance | |
| sqlite3_c_api.swift:43:49:43:49 | medicalNotes | sqlite3_c_api.swift:47:27:47:27 | updateQuery | provenance | |
| testCoreData2.swift:23:13:23:13 | value | file://:0:0:0:0 | value | provenance | |
@@ -294,9 +296,38 @@ edges
| testGRDB.swift:212:98:212:107 | [...] [Collection element] | testGRDB.swift:212:98:212:107 | [...] | provenance | |
| testGRDB.swift:212:99:212:99 | password | testGRDB.swift:212:98:212:107 | [...] [Collection element] | provenance | |
| testRealm2.swift:13:6:13:6 | value | file://:0:0:0:0 | value | provenance | |
| testRealm2.swift:13:6:13:6 | value [Collection element] | file://:0:0:0:0 | value [Collection element] | provenance | |
| testRealm2.swift:18:2:18:2 | [post] o [data] | testRealm2.swift:18:2:18:2 | [post] o | provenance | |
| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:13:6:13:6 | value | provenance | |
| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:18:2:18:2 | [post] o [data] | provenance | |
| testRealm2.swift:24:2:24:2 | [post] o [data] | testRealm2.swift:24:2:24:2 | [post] o | provenance | |
| testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:13:6:13:6 | value | provenance | |
| testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:24:2:24:2 | [post] o [data] | provenance | |
| testRealm2.swift:25:2:25:2 | [post] o [data] | testRealm2.swift:25:2:25:2 | [post] o | provenance | |
| testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:13:6:13:6 | value | provenance | |
| testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:25:2:25:2 | [post] o [data] | provenance | |
| testRealm2.swift:26:2:26:2 | [post] o [data, Collection element] | testRealm2.swift:26:2:26:2 | [post] o | provenance | |
| testRealm2.swift:26:2:26:2 | [post] o [data] | testRealm2.swift:26:2:26:2 | [post] o | provenance | |
| testRealm2.swift:26:11:26:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | provenance | |
| testRealm2.swift:26:11:26:25 | call to String.init(_:) | testRealm2.swift:26:2:26:2 | [post] o [data] | provenance | |
| testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | provenance | |
| testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | testRealm2.swift:26:2:26:2 | [post] o [data, Collection element] | provenance | |
| testRealm2.swift:26:18:26:18 | ssn_int | testRealm2.swift:26:11:26:25 | call to String.init(_:) | provenance | |
| testRealm2.swift:26:18:26:18 | ssn_int | testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | provenance | |
| testRealm2.swift:32:2:32:2 | [post] o [data] | testRealm2.swift:32:2:32:2 | [post] o | provenance | |
| testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:13:6:13:6 | value | provenance | |
| testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:32:2:32:2 | [post] o [data] | provenance | |
| testRealm2.swift:33:2:33:2 | [post] o [data] | testRealm2.swift:33:2:33:2 | [post] o | provenance | |
| testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:13:6:13:6 | value | provenance | |
| testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:33:2:33:2 | [post] o [data] | provenance | |
| testRealm2.swift:34:2:34:2 | [post] o [data, Collection element] | testRealm2.swift:34:2:34:2 | [post] o | provenance | |
| testRealm2.swift:34:2:34:2 | [post] o [data] | testRealm2.swift:34:2:34:2 | [post] o | provenance | |
| testRealm2.swift:34:11:34:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | provenance | |
| testRealm2.swift:34:11:34:25 | call to String.init(_:) | testRealm2.swift:34:2:34:2 | [post] o [data] | provenance | |
| testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | provenance | |
| testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | testRealm2.swift:34:2:34:2 | [post] o [data, Collection element] | provenance | |
| testRealm2.swift:34:18:34:18 | int_ccn | testRealm2.swift:34:11:34:25 | call to String.init(_:) | provenance | |
| testRealm2.swift:34:18:34:18 | int_ccn | testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | provenance | |
| testRealm.swift:27:6:27:6 | value | file://:0:0:0:0 | value | provenance | |
| testRealm.swift:34:6:34:6 | value | file://:0:0:0:0 | value | provenance | |
| testRealm.swift:41:2:41:2 | [post] a [data] | testRealm.swift:41:2:41:2 | [post] a | provenance | |
@@ -413,6 +444,7 @@ nodes
| file://:0:0:0:0 | .value | semmle.label | .value |
| file://:0:0:0:0 | .value | semmle.label | .value |
| file://:0:0:0:0 | .value2 | semmle.label | .value2 |
| file://:0:0:0:0 | [post] self [data, Collection element] | semmle.label | [post] self [data, Collection element] |
| file://:0:0:0:0 | [post] self [data] | semmle.label | [post] self [data] |
| file://:0:0:0:0 | [post] self [data] | semmle.label | [post] self [data] |
| file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] | semmle.label | [post] self [notStoredBankAccountNumber] |
@@ -426,6 +458,7 @@ nodes
| file://:0:0:0:0 | value | semmle.label | value |
| file://:0:0:0:0 | value | semmle.label | value |
| file://:0:0:0:0 | value | semmle.label | value |
| file://:0:0:0:0 | value [Collection element] | semmle.label | value [Collection element] |
| sqlite3_c_api.swift:42:69:42:69 | medicalNotes | semmle.label | medicalNotes |
| sqlite3_c_api.swift:43:49:43:49 | medicalNotes | semmle.label | medicalNotes |
| sqlite3_c_api.swift:46:27:46:27 | insertQuery | semmle.label | insertQuery |
@@ -716,11 +749,37 @@ nodes
| testGRDB.swift:212:98:212:107 | [...] | semmle.label | [...] |
| testGRDB.swift:212:98:212:107 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| testGRDB.swift:212:99:212:99 | password | semmle.label | password |
| testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | semmle.label | self [Return] [data, Collection element] |
| testRealm2.swift:13:6:13:6 | self [Return] [data] | semmle.label | self [Return] [data] |
| testRealm2.swift:13:6:13:6 | value | semmle.label | value |
| testRealm2.swift:13:6:13:6 | value [Collection element] | semmle.label | value [Collection element] |
| testRealm2.swift:18:2:18:2 | [post] o | semmle.label | [post] o |
| testRealm2.swift:18:2:18:2 | [post] o [data] | semmle.label | [post] o [data] |
| testRealm2.swift:18:11:18:11 | myPassword | semmle.label | myPassword |
| testRealm2.swift:24:2:24:2 | [post] o | semmle.label | [post] o |
| testRealm2.swift:24:2:24:2 | [post] o [data] | semmle.label | [post] o [data] |
| testRealm2.swift:24:11:24:11 | socialSecurityNumber | semmle.label | socialSecurityNumber |
| testRealm2.swift:25:2:25:2 | [post] o | semmle.label | [post] o |
| testRealm2.swift:25:2:25:2 | [post] o [data] | semmle.label | [post] o [data] |
| testRealm2.swift:25:11:25:11 | ssn | semmle.label | ssn |
| testRealm2.swift:26:2:26:2 | [post] o | semmle.label | [post] o |
| testRealm2.swift:26:2:26:2 | [post] o [data, Collection element] | semmle.label | [post] o [data, Collection element] |
| testRealm2.swift:26:2:26:2 | [post] o [data] | semmle.label | [post] o [data] |
| testRealm2.swift:26:11:26:25 | call to String.init(_:) | semmle.label | call to String.init(_:) |
| testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] |
| testRealm2.swift:26:18:26:18 | ssn_int | semmle.label | ssn_int |
| testRealm2.swift:32:2:32:2 | [post] o | semmle.label | [post] o |
| testRealm2.swift:32:2:32:2 | [post] o [data] | semmle.label | [post] o [data] |
| testRealm2.swift:32:11:32:11 | creditCardNumber | semmle.label | creditCardNumber |
| testRealm2.swift:33:2:33:2 | [post] o | semmle.label | [post] o |
| testRealm2.swift:33:2:33:2 | [post] o [data] | semmle.label | [post] o [data] |
| testRealm2.swift:33:11:33:11 | CCN | semmle.label | CCN |
| testRealm2.swift:34:2:34:2 | [post] o | semmle.label | [post] o |
| testRealm2.swift:34:2:34:2 | [post] o [data, Collection element] | semmle.label | [post] o [data, Collection element] |
| testRealm2.swift:34:2:34:2 | [post] o [data] | semmle.label | [post] o [data] |
| testRealm2.swift:34:11:34:25 | call to String.init(_:) | semmle.label | call to String.init(_:) |
| testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] |
| testRealm2.swift:34:18:34:18 | int_ccn | semmle.label | int_ccn |
| testRealm.swift:27:6:27:6 | self [Return] [data] | semmle.label | self [Return] [data] |
| testRealm.swift:27:6:27:6 | value | semmle.label | value |
| testRealm.swift:34:6:34:6 | self [Return] [password] | semmle.label | self [Return] [password] |
@@ -756,6 +815,14 @@ subpaths
| testCoreData2.swift:104:18:104:18 | e | testCoreData2.swift:70:9:70:9 | self | file://:0:0:0:0 | .value | testCoreData2.swift:104:18:104:20 | .value |
| testCoreData2.swift:105:18:105:18 | e | testCoreData2.swift:71:9:71:9 | self | file://:0:0:0:0 | .value2 | testCoreData2.swift:105:18:105:20 | .value2 |
| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:18:2:18:2 | [post] o [data] |
| testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:24:2:24:2 | [post] o [data] |
| testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:25:2:25:2 | [post] o [data] |
| testRealm2.swift:26:11:26:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:26:2:26:2 | [post] o [data] |
| testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | testRealm2.swift:26:2:26:2 | [post] o [data, Collection element] |
| testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:32:2:32:2 | [post] o [data] |
| testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:33:2:33:2 | [post] o [data] |
| testRealm2.swift:34:11:34:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:34:2:34:2 | [post] o [data] |
| testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | testRealm2.swift:34:2:34:2 | [post] o [data, Collection element] |
| testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:41:2:41:2 | [post] a [data] |
| testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:49:2:49:2 | [post] c [data] |
| testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:59:2:59:3 | [post] ...! [data] |
@@ -890,6 +957,12 @@ subpaths
| testGRDB.swift:210:84:210:93 | [...] | testGRDB.swift:210:85:210:85 | password | testGRDB.swift:210:84:210:93 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:210:85:210:85 | password | password |
| testGRDB.swift:212:98:212:107 | [...] | testGRDB.swift:212:99:212:99 | password | testGRDB.swift:212:98:212:107 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:212:99:212:99 | password | password |
| testRealm2.swift:18:2:18:2 | o | testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:18:2:18:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:18:11:18:11 | myPassword | myPassword |
| testRealm2.swift:24:2:24:2 | o | testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:24:2:24:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:24:11:24:11 | socialSecurityNumber | socialSecurityNumber |
| testRealm2.swift:25:2:25:2 | o | testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:25:2:25:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:25:11:25:11 | ssn | ssn |
| testRealm2.swift:26:2:26:2 | o | testRealm2.swift:26:18:26:18 | ssn_int | testRealm2.swift:26:2:26:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:26:18:26:18 | ssn_int | ssn_int |
| testRealm2.swift:32:2:32:2 | o | testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:32:2:32:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:32:11:32:11 | creditCardNumber | creditCardNumber |
| testRealm2.swift:33:2:33:2 | o | testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:33:2:33:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:33:11:33:11 | CCN | CCN |
| testRealm2.swift:34:2:34:2 | o | testRealm2.swift:34:18:34:18 | int_ccn | testRealm2.swift:34:2:34:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:34:18:34:18 | int_ccn | int_ccn |
| testRealm.swift:41:2:41:2 | a | testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:41:2:41:2 | [post] a | This operation stores 'a' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:41:11:41:11 | myPassword | myPassword |
| testRealm.swift:49:2:49:2 | c | testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:49:2:49:2 | [post] c | This operation stores 'c' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:49:11:49:11 | myPassword | myPassword |
| testRealm.swift:59:2:59:3 | ...! | testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:59:2:59:3 | [post] ...! | This operation stores '...!' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:59:12:59:12 | myPassword | myPassword |

View File

@@ -141,6 +141,12 @@
| testGRDB.swift:210:85:210:85 | password | label:password, type:password |
| testGRDB.swift:212:99:212:99 | password | label:password, type:password |
| testRealm2.swift:18:11:18:11 | myPassword | label:myPassword, type:password |
| testRealm2.swift:24:11:24:11 | socialSecurityNumber | label:socialSecurityNumber, type:private information |
| testRealm2.swift:25:11:25:11 | ssn | label:ssn, type:private information |
| testRealm2.swift:26:18:26:18 | ssn_int | label:ssn_int, type:private information |
| testRealm2.swift:32:11:32:11 | creditCardNumber | label:creditCardNumber, type:private information |
| testRealm2.swift:33:11:33:11 | CCN | label:CCN, type:private information |
| testRealm2.swift:34:18:34:18 | int_ccn | label:int_ccn, type:private information |
| testRealm.swift:31:20:31:20 | .password | label:password, type:password |
| testRealm.swift:41:11:41:11 | myPassword | label:myPassword, type:password |
| testRealm.swift:49:11:49:11 | myPassword | label:myPassword, type:password |

View File

@@ -13,9 +13,25 @@ class MyRealmSwiftObject3 : Object {
var data: String
}
func test1(o: MyRealmSwiftObject3, myHarmless: String, myPassword : String) {
func test1(o: MyRealmSwiftObject3, myHarmless: String, myPassword: String) {
// ...
o.data = myPassword // BAD
o.data = myHarmless
// ...
}
func test2(o: MyRealmSwiftObject3, ccn: String, socialSecurityNumber: String, ssn: String, ssn_int: Int, userSSN: String, classno: String) {
o.data = socialSecurityNumber // BAD
o.data = ssn // BAD
o.data = String(ssn_int) // BAD
o.data = userSSN // BAD [NOT DETECTED]
o.data = classno // GOOD
}
func test3(o: MyRealmSwiftObject3, ccn: String, creditCardNumber: String, CCN: String, int_ccn: Int, userCcn: String, succnode: String) {
o.data = creditCardNumber // BAD
o.data = CCN // BAD
o.data = String(int_ccn) // BAD
o.data = userCcn // BAD [NOT DETECTED]
o.data = succnode // GOOD
}