Skip to content

Commit 964c924

Browse files
committed
Swift: Test SQL injection via the C API.
1 parent bcab9d8 commit 964c924

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,163 @@
11

22
// --- stubs ---
33

4+
struct URL
5+
{
6+
init?(string: String) {}
7+
init?(string: String, relativeTo: URL?) {}
8+
}
9+
10+
extension String {
11+
init(contentsOf: URL) throws {
12+
var data = ""
13+
14+
// ...
15+
16+
self.init(data)
17+
}
18+
}
19+
20+
var SQLITE_OK : Int32 = 0
21+
var SQLITE_TRANSIENT : (@convention(c) (UnsafeMutableRawPointer?) -> Void)?
22+
23+
func sqlite3_exec(
24+
_ _: OpaquePointer?,
25+
_ sql: UnsafePointer<CChar>?,
26+
_ callback: (@convention(c) (UnsafeMutableRawPointer?, Int32, UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?, UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?) -> Int32)?,
27+
_ _: UnsafeMutableRawPointer?,
28+
_ errmsg: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
29+
) -> Int32 { return SQLITE_OK }
30+
31+
func sqlite3_prepare(
32+
_ db: OpaquePointer?,
33+
_ zSql: UnsafePointer<CChar>?,
34+
_ nByte: Int32,
35+
_ ppStmt: UnsafeMutablePointer<OpaquePointer?>?,
36+
_ pzTail: UnsafeMutablePointer<UnsafePointer<CChar>?>?
37+
) -> Int32 { return SQLITE_OK }
38+
39+
func sqlite3_prepare_v2(
40+
_ db: OpaquePointer?,
41+
_ zSql: UnsafePointer<CChar>?,
42+
_ nByte: Int32,
43+
_ ppStmt: UnsafeMutablePointer<OpaquePointer?>?,
44+
_ pzTail: UnsafeMutablePointer<UnsafePointer<CChar>?>?
45+
) -> Int32 { return SQLITE_OK }
46+
47+
func sqlite3_prepare_v3(
48+
_ db: OpaquePointer?,
49+
_ zSql: UnsafePointer<CChar>?,
50+
_ nByte: Int32,
51+
_ prepFlags: UInt32,
52+
_ ppStmt: UnsafeMutablePointer<OpaquePointer?>?,
53+
_ pzTail: UnsafeMutablePointer<UnsafePointer<CChar>?>?
54+
) -> Int32 { return SQLITE_OK }
55+
56+
func sqlite3_prepare16(
57+
_ db: OpaquePointer?,
58+
_ zSql: UnsafeRawPointer?,
59+
_ nByte: Int32,
60+
_ ppStmt: UnsafeMutablePointer<OpaquePointer?>?,
61+
_ pzTail: UnsafeMutablePointer<UnsafeRawPointer?>?
62+
) -> Int32 { return SQLITE_OK }
63+
64+
func sqlite3_prepare16_v2(
65+
_ db: OpaquePointer?,
66+
_ zSql: UnsafeRawPointer?,
67+
_ nByte: Int32,
68+
_ ppStmt: UnsafeMutablePointer<OpaquePointer?>?,
69+
_ pzTail: UnsafeMutablePointer<UnsafeRawPointer?>?
70+
) -> Int32 { return SQLITE_OK }
71+
72+
func sqlite3_prepare16_v3(
73+
_ db: OpaquePointer?,
74+
_ zSql: UnsafeRawPointer?,
75+
_ nByte: Int32,
76+
_ prepFlags: UInt32,
77+
_ ppStmt: UnsafeMutablePointer<OpaquePointer?>?,
78+
_ pzTail: UnsafeMutablePointer<UnsafeRawPointer?>?
79+
) -> Int32 { return SQLITE_OK }
80+
81+
func sqlite3_bind_text(
82+
_ _: OpaquePointer?,
83+
_ _: Int32,
84+
_ _: UnsafePointer<CChar>?,
85+
_ _: Int32,
86+
_ callback: (@convention(c) (UnsafeMutableRawPointer?) -> Void)?
87+
) -> Int32 { return SQLITE_OK }
88+
// (many other `sqlite3_bind_*` functions exist)
89+
90+
func sqlite3_step(
91+
_ _: OpaquePointer?
92+
) -> Int32 { return SQLITE_OK }
93+
94+
func sqlite3_finalize(
95+
_ pStmt: OpaquePointer?
96+
) -> Int32 { return SQLITE_OK }
97+
98+
func sanitize(_ string: String) -> String { return string }
99+
4100
// --- tests ---
101+
102+
func test_sqlite3_c_api(db: OpaquePointer?) {
103+
let localString = "user"
104+
let remoteString = try! String(contentsOf: URL(string: "http://example.com/")!)
105+
let sanitizedString = sanitize(remoteString)
106+
107+
let unsafeQuery1 = remoteString
108+
let unsafeQuery2 = "SELECT * FROM users WHERE username='" + remoteString + "'"
109+
let unsafeQuery3 = "SELECT * FROM users WHERE username='\(remoteString)'"
110+
let safeQuery1 = "SELECT * FROM users WHERE username='\(localString)'"
111+
let safeQuery2 = "SELECT * FROM users WHERE username='\(sanitizedString)'"
112+
let varQuery = "SELECT * FROM users WHERE username=?"
113+
114+
// --- exec ---
115+
116+
let result1 = sqlite3_exec(db, unsafeQuery1, nil, nil, nil) // BAD
117+
let result2 = sqlite3_exec(db, unsafeQuery2, nil, nil, nil) // BAD
118+
let result3 = sqlite3_exec(db, unsafeQuery3, nil, nil, nil) // BAD
119+
let result4 = sqlite3_exec(db, safeQuery1, nil, nil, nil) // GOOD
120+
let result5 = sqlite3_exec(db, safeQuery2, nil, nil, nil) // GOOD (sanitized)
121+
122+
// --- prepared statements ---
123+
124+
var stmt1: OpaquePointer?
125+
126+
if (sqlite3_prepare(db, unsafeQuery3, -1, &stmt1, nil) == SQLITE_OK) { // BAD
127+
let result = sqlite3_step(stmt1)
128+
// ...
129+
}
130+
sqlite3_finalize(stmt1)
131+
132+
var stmt2: OpaquePointer?
133+
134+
if (sqlite3_prepare(db, varQuery, -1, &stmt2, nil) == SQLITE_OK) { // GOOD
135+
if (sqlite3_bind_text(stmt2, 1, localString, -1, SQLITE_TRANSIENT) == SQLITE_OK) { // GOOD
136+
let result = sqlite3_step(stmt2)
137+
// ...
138+
}
139+
}
140+
sqlite3_finalize(stmt2)
141+
142+
var stmt3: OpaquePointer?
143+
144+
if (sqlite3_prepare(db, varQuery, -1, &stmt3, nil) == SQLITE_OK) { // GOOD
145+
if (sqlite3_bind_text(stmt3, 1, sanitizedString, -1, SQLITE_TRANSIENT) == SQLITE_OK) { // GOOD
146+
let result = sqlite3_step(stmt3)
147+
// ...
148+
}
149+
}
150+
sqlite3_finalize(stmt3)
151+
152+
var stmt4: OpaquePointer?
153+
154+
if (sqlite3_prepare_v2(db, varQuery, -1, &stmt4, nil) == SQLITE_OK) { // GOOD
155+
if (sqlite3_bind_text(stmt4, 1, remoteString, -1, SQLITE_TRANSIENT) == SQLITE_OK) { // GOOD???
156+
let result = sqlite3_step(stmt4)
157+
// ...
158+
}
159+
}
160+
sqlite3_finalize(stmt4)
161+
162+
// TODO: use all versions v3, 16 etc.
163+
}

0 commit comments

Comments
 (0)