Skip to content

Commit

Permalink
Add Swift rules (#3034)
Browse files Browse the repository at this point in the history
* Add Swift rules

* add nosemgrep

* add category

* add nosemgrep

* fix name conflict
  • Loading branch information
LewisArdern authored Aug 11, 2023
1 parent 4c49b7a commit d5bec93
Show file tree
Hide file tree
Showing 6 changed files with 362 additions and 0 deletions.
35 changes: 35 additions & 0 deletions swift/lang/storage/sensitive-storage-userdefaults.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
let username = getUsername()
let passphrase = getPass()


// okid: swift-user-defaults
UserDefaults.standard.set(username, forKey: "userName")
// ruleid: swift-user-defaults
UserDefaults.standard.set(passphrase, forKey: "passphrase")
// ruleid: swift-user-defaults
UserDefaults.standard.set(passWord, forKey: "userPassword")

// ruleid: swift-user-defaults
UserDefaults.standard.set("12717-127163-a71367-127ahc", forKey: "apiKey")

let apiKey = "12717-127163-a71367-127ahc"
// ruleid: swift-user-defaults
UserDefaults.standard.set(apiKey, forKey: "GOOGLE_TOKEN")


let key = "1sdad3SADSD33131"
// ruleid: swift-user-defaults
UserDefaults.standard.set(key, forKey: "cryptoKey")


let key = "foobar"
// ruleid: swift-user-defaults
UserDefaults.standard.set(key, forKey: "clientSecret")


let key = "foobar"
// ruleid: swift-user-defaults
UserDefaults.standard.set(key, forKey: "rsaPrivateKey")

// ruleid: swift-user-defaults
UserDefaults.standard.set(passphrase, forKey: "pass_phrase")
144 changes: 144 additions & 0 deletions swift/lang/storage/sensitive-storage-userdefaults.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
rules:
- id: swift-user-defaults
message: >-
Potentially sensitive data was observed to be stored in UserDefaults, which is not adequate protection
of sensitive information. For data of a sensitive nature, applications should leverage the Keychain.
severity: WARNING
metadata:
likelihood: LOW
impact: HIGH
confidence: MEDIUM
category: security
cwe:
- 'CWE-311: Missing Encryption of Sensitive Data'
masvs:
- 'MASVS-STORAGE-1: The app securely stores sensitive data'
owasp:
- A03:2017 - Sensitive Data Exposure
- A04:2021 - Insecure Design
references:
- https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/ValidatingInput.html
- https://mas.owasp.org/MASVS/controls/MASVS-STORAGE-1/
subcategory:
- vuln
technology:
- ios
- macos
languages:
- swift
options:
taint_propagation: true
patterns:
- pattern-either:
- patterns:
- pattern-either:
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: "$KEY")
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: $KEY)
- pattern: |
UserDefaults.standard.set($VALUE, forKey: "$KEY")
- pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
- metavariable-regex:
metavariable: $VALUE
regex: (?i).*(passcode|password|pass_word|passphrase|pass_code|pass_word|pass_phrase)$
- focus-metavariable: $VALUE
- patterns:
- pattern-either:
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: "$KEY")
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: $KEY)
- pattern: |
UserDefaults.standard.set($VALUE, forKey: "$KEY")
- pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
- metavariable-regex:
metavariable: $KEY
regex: (?i).*(passcode|password|pass_word|passphrase|pass_code|pass_word|pass_phrase)$
- focus-metavariable: $KEY
- patterns:
- pattern-either:
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: "$KEY")
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: $KEY)
- pattern: |
UserDefaults.standard.set($VALUE, forKey: "$KEY")
- pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
- metavariable-regex:
metavariable: $VALUE
regex: (?i).*(api_key|apikey)$
- focus-metavariable: $VALUE
- patterns:
- pattern-either:
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: "$KEY")
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: $KEY)
- pattern: |
UserDefaults.standard.set($VALUE, forKey: "$KEY")
- pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
- metavariable-regex:
metavariable: $KEY
regex: (?i).*(api_key|apikey)$
- focus-metavariable: $KEY
- patterns:
- pattern-either:
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: "$KEY")
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: $KEY)
- pattern: |
UserDefaults.standard.set($VALUE, forKey: "$KEY")
- pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
- metavariable-regex:
metavariable: $VALUE
regex: (?i).*(secretkey|secret_key|secrettoken|secret_token|clientsecret|client_secret)$
- focus-metavariable: $VALUE
- patterns:
- pattern-either:
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: "$KEY")
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: $KEY)
- pattern: |
UserDefaults.standard.set($VALUE, forKey: "$KEY")
- pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
- metavariable-regex:
metavariable: $KEY
regex: (?i).*(secretkey|secret_key|secrettoken|secret_token|clientsecret|client_secret)$
- focus-metavariable: $KEY
- patterns:
- pattern-either:
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: "$KEY")
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: $KEY)
- pattern: |
UserDefaults.standard.set($VALUE, forKey: "$KEY")
- pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
- metavariable-regex:
metavariable: $VALUE
regex: (?i).*(cryptkey|cryptokey|crypto_key|cryptionkey|symmetrickey|privatekey|symmetric_key|private_key)$
- focus-metavariable: $VALUE
- patterns:
- pattern-either:
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: "$KEY")
- pattern: |
UserDefaults.standard.set("$VALUE", forKey: $KEY)
- pattern: |
UserDefaults.standard.set($VALUE, forKey: "$KEY")
- pattern: |
UserDefaults.standard.set($VALUE, forKey: $KEY)
- metavariable-regex:
metavariable: $KEY
regex: (?i).*(cryptkey|cryptokey|crypto_key|cryptionkey|symmetrickey|privatekey|symmetric_key|private_key)$
- focus-metavariable: $KEY
66 changes: 66 additions & 0 deletions swift/sqllite/sqllite-injection-audit.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
let username = someField.text()
let password = a.text()

let sql = "SELECT * FROM semgrep_users WHERE username = '\(username)' AND password = '\(password)'"

// ruleid:swift-potential-sqlite-injection
let result = sqlite3_exec(db, sql, nil, nil, nil)
sqlite3_close(db)

let sql = "SELECT * FROM semgrep_users WHERE username = 'admin' AND password = '\(password)'"
// ruleid:swift-potential-sqlite-injection
let result = sqlite3_exec(db, sql, nil, nil, nil)
sqlite3_close(db)


let sql = "SELECT * FROM semgrep_users WHERE username = ? AND password = ?"
var stmt: OpaquePointer?
// okid:swift-potential-sqlite-injection
if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) == SQLITE_OK {
sqlite3_bind_text(stmt, 1, username, -1, nil)
sqlite3_bind_text(stmt, 2, password, -1, nil)
if sqlite3_step(stmt) == SQLITE_DONE {
// SUCCESS
}
}

sqlite3_finalize(stmt)
sqlite3_close(db)

let sql = "SELECT * FROM semgrep_users WHERE username = 'admin' AND password = 'admin'"
// okid:swift-potential-sqlite-injection
let result = sqlite3_exec(db, sql, nil, nil, nil)
sqlite3_close(db)


let theUsername = "admin"
let sql = "SELECT * FROM semgrep_users WHERE username = '" + theUsername + "' AND password = 'admin'"
// FP but cant do much about this I dont think
// ruleid:swift-potential-sqlite-injection
let result = sqlite3_exec(db, sql, nil, nil, nil)
sqlite3_close(db)

let newUser = getUsernameFromServer()
let sql = "SELECT * FROM semgrep_users WHERE username = '" + newUser + "' AND password = 'admin'"
// ruleid:swift-potential-sqlite-injection
let result = sqlite3_exec(db, sql, nil, nil, nil)
sqlite3_close(db)


let sql = "SELECT * FROM semgrep_users WHERE username = 'admin' AND password = '" + password + "'"
// ruleid:swift-potential-sqlite-injection
let result = sqlite3_exec(db, sql, nil, nil, nil)
sqlite3_close(db)


let sql = "SELECT * FROM semgrep_users WHERE username = ? AND password = '" + password + "'"
// ruleid:swift-potential-sqlite-injection
if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) == SQLITE_OK {
sqlite3_bind_text(stmt, 1, username, -1, nil)
if sqlite3_step(stmt) == SQLITE_DONE {
// SUCCESS
}
}

sqlite3_finalize(stmt)
sqlite3_close(db)
43 changes: 43 additions & 0 deletions swift/sqllite/sqllite-injection-audit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
rules:
- id: swift-potential-sqlite-injection
message: >-
Potential Client-side SQL injection which has different impacts depending on the SQL use-case. The
impact may include the circumvention of local authentication mechanisms, obtaining of sensitive data
from the app, or manipulation of client-side behavior. It wasn't possible to make certain that the
source is untrusted, but the application should avoid concatenating dynamic data into SQL queries
and should instead leverage parameterized queries.
severity: WARNING
metadata:
likelihood: MEDIUM
impact: MEDIUM
confidence: LOW
category: security
cwe:
- "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')"
masvs:
- 'MASVS-CODE-4: The app validates and sanitizes all untrusted inputs.'
references:
- https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/ValidatingInput.html
subcategory:
- vuln
technology:
- ios
- macos
languages:
- swift
mode: taint
pattern-sources:
- pattern-either:
- pattern: |
"...\($X)..."
- pattern: |
$SQL = "..." + $X
- pattern: |
$SQL = $X + "..."
pattern-sinks:
- patterns:
- pattern-either:
- pattern: sqlite3_exec($DB, $SQL, ...)
- pattern: sqlite3_prepare_v2($DB, $SQL, ...)
- focus-metavariable:
- $SQL
16 changes: 16 additions & 0 deletions swift/webview/webview-js-window.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
let prefs = WKPreferences()
// ruleid: swift-webview-config-allows-js-open-windows
prefs.JavaScriptCanOpenWindowsAutomatically = true
let config = WKWebViewConfiguration()
config.defaultWebpagePreferences = prefs

WKWebView(frame: .zero, configuration: config)

let prefs2 = WKPreferences()
prefs2.JavaScriptCanOpenWindowsAutomatically = true
// okid: swift-webview-config-allows-js-open-windows
prefs2.JavaScriptCanOpenWindowsAutomatically = false
let config = WKWebViewConfiguration()
config.defaultWebpagePreferences = prefs2

WKWebView(frame: .zero, configuration: config)
58 changes: 58 additions & 0 deletions swift/webview/webview-js-window.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
rules:
- id: swift-webview-config-allows-js-open-windows
message: >-
Webviews were observed that explictly allow JavaScript in an WKWebview to open windows automatically.
Consider disabling this functionality if not required, following the principle of least privelege.
severity: WARNING
metadata:
likelihood: LOW
impact: LOW
confidence: HIGH
category: security
cwe:
- 'CWE-272: Least Privilege Violation'
masvs:
- 'MASVS-PLATFORM-2: The app uses WebViews securely'
references:
- https://mas.owasp.org/MASVS/controls/MASVS-PLATFORM-2/
- https://developer.apple.com/documentation/webkit/wkpreferences/1536573-javascriptcanopenwindowsautomati
subcategory:
- audit
technology:
- ios
- macos
languages:
- swift
patterns:
- pattern: |
$P = WKPreferences()
...
- pattern-either:
- patterns:
- pattern-inside: |
$P.JavaScriptCanOpenWindowsAutomatically = $FALSE
...
$P.JavaScriptCanOpenWindowsAutomatically = $TRUE
# nosemgrep
- pattern-not-inside: |
...
$P.JavaScriptCanOpenWindowsAutomatically = $TRUE
...
$P.JavaScriptCanOpenWindowsAutomatically = $FALSE
- pattern: |
$P.JavaScriptCanOpenWindowsAutomatically = true
- metavariable-regex:
metavariable: $TRUE
regex: ^(true)$
- metavariable-regex:
metavariable: $TRUE
regex: (.*(?!true))
- patterns:
- pattern: |
$P.JavaScriptCanOpenWindowsAutomatically = true
# nosemgrep
- pattern-not-inside: |
...
$P.JavaScriptCanOpenWindowsAutomatically = ...
...
$P.JavaScriptCanOpenWindowsAutomatically = ...

0 comments on commit d5bec93

Please sign in to comment.