Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift: Query for SQL injection #10757

Merged
merged 23 commits into from Oct 20, 2022
Merged

Swift: Query for SQL injection #10757

merged 23 commits into from Oct 20, 2022

Conversation

geoffw0
Copy link
Contributor

@geoffw0 geoffw0 commented Oct 10, 2022

Query for SQL injection in Swift.

Draft: currently there are just test cases, covering the C API that can be used in Swift, and the SQLite.swift wrapper that I believe is commonly used as well. I'd like someone to review these test cases for realism / misconceptions / any important details I've missed before going too much further.

@atorralba would you mind taking a look?

@geoffw0 geoffw0 added no-change-note-required This PR does not need a change note Swift labels Oct 10, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Oct 10, 2022

QHelp previews:

swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp

SQL query built from user-controlled sources

TODO

Recommendation

TODO

Example

TODO


TODO

TODO


TODO

References

  • TODO
  • Common Weakness Enumeration: CWE-89.

Copy link
Contributor

@atorralba atorralba left a comment

The tests make sense to me. sqlite3_exec and sqlite3_prepare* seem to be the appropriate sinks, because they handle raw SQL statements. sqlite3_bind* handle the parameters of prepared statements, which is safe to do even with untrusted data.

This should cover the raw sqlite3 library. Are we planning on covering wrapper libraries on top of it? e.g. https://github.com/stephencelis/SQLite.swift or https://github.com/groue/GRDB.swift.

@geoffw0
Copy link
Contributor Author

geoffw0 commented Oct 11, 2022

Are we planning on covering wrapper libraries on top of it? e.g. https://github.com/stephencelis/SQLite.swift

The tests in SQLite.swift should cover this library - assuming I've correctly identified the right / most important interfaces.

or https://github.com/groue/GRDB.swift.

Yeah it would be good to cover this library as well. However I'm a bit behind on this task as it is, so I'll create a follow-up ticket rather than addressing this now. --- update: added to the query priorities board.

Copy link
Contributor

@atorralba atorralba left a comment

The tests in SQLite.swift should cover this library - assuming I've correctly identified the right / most important interfaces.

D'oh, true, sorry.

swift/ql/test/query-tests/Security/CWE-089/SQLite.swift Outdated Show resolved Hide resolved
swift/ql/test/query-tests/Security/CWE-089/SQLite.swift Outdated Show resolved Hide resolved
@github-actions
Copy link
Contributor

github-actions bot commented Oct 14, 2022

QHelp previews:

swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp

errors/warnings:

./swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp:35:6: element "li" not allowed here; expected the element end-tag, text or element "a", "b", "blockquote", "code", "em", "i", "img", "ol", "p", "pre", "sample", "strong", "sub", "sup", "table", "tt", "ul" or "warning"
./swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp:36:6: element "li" not allowed here; expected the element end-tag, text or element "a", "b", "blockquote", "code", "em", "i", "img", "ol", "p", "pre", "sample", "strong", "sub", "sup", "table", "tt", "ul" or "warning"
A fatal error occurred: 1 qhelp files could not be processed.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 14, 2022

QHelp previews:

swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp

Database query built from user-controlled sources

If a database query (such as a SQL query) is built from user-provided data without sufficient sanitization, a user may be able to run malicious database queries. An attacker can craft the part of the query they control to change the overall meaning of the query.

Recommendation

Most database connector libraries offer a way to safely embed untrusted data into a query using query parameters or prepared statements. You should use these features to build queries, rather than string concatenation or similar methods without sufficient sanitization.

Example

In the following example, a SQL query is prepared using string interpolation to directly include a user-controlled value userControlledString in the query. An attacker could craft userControlledString to change the overall meaning of the SQL query.

let unsafeQuery = "SELECT * FROM users WHERE username='\(userControlledString)'" // BAD

try db.execute(unsafeQuery)

A better way to do this is with a prepared statement, binding userControlledString to a parameter of that statement. An attacker who controls userControlledString now cannot change the overall meaning of the query.

let safeQuery = "SELECT * FROM users WHERE username=?"

let stmt = try db.prepare(safeQuery, userControlledString) // GOOD
try stmt2.run()

References

@geoffw0 geoffw0 marked this pull request as ready for review Oct 14, 2022
@geoffw0 geoffw0 requested a review from a team as a code owner Oct 14, 2022
@geoffw0
Copy link
Contributor Author

geoffw0 commented Oct 14, 2022

I've removed draft status from this PR, it's ready to review.

I'd like to acknowledge a few issues though. IMO none of these prevent us from merging what we have:

  • we're getting no results on the C API test due to an issue with taint flow, possibly itself caused by an extractor issue. I'm discussing this with other members of the team and I'm not sure if the fix will be something simple I can do here, or something that will need to be done as follow-up.
    • this has been fixed, though there is still an issue with the UTF-16 results (probably a missing taint flow step).
  • there are no sanitizers for remote data in numerical form yet (considered to be safe). This is because in my test case taint doesn't flow into remoteNumber anyway, so there's no way to test such a sanitizer (and no strict need for it yet).
  • we may also want sanitizers along the lines of Ruby's StringConstCompareBarrier and StringConstArrayInclusionCallBarrier. I might write a follow-up issue for this but I'm inclined not to worry too much until we see patterns like those in real Swift code (they are talked about in https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html).

@geoffw0
Copy link
Contributor Author

geoffw0 commented Oct 17, 2022

I've just merged main into this PR - with the extractor fix #10854 that gives us the C API results for this query. We still don't get results through the UTF-16 interface, but that's much less concerning than missing all C API results.

I'd be happy to see this reviewed and merged, and deal with the remaining known issues as follow-up.

jketema
jketema previously approved these changes Oct 18, 2022
Copy link
Contributor

@jketema jketema left a comment

Two small questions. Otherwise this looks ok to me.

stmt9.bind(remoteString)
stmt9.bind([remoteString])
stmt9.bind(["username": remoteString])
try stmt9.run(remoteString)
try stmt9.run([remoteString])
try stmt9.run(["username": remoteString])
try stmt9.scalar(remoteString)
try stmt9.scalar([remoteString])
try stmt9.scalar(["username": remoteString])
Copy link
Contributor

@jketema jketema Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These I do not quite understand, even after looking at the SQLite.swift docs. Shouldn't these be tagged with // GOOD, or am I missing something?

Copy link
Contributor Author

@geoffw0 geoffw0 Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this whole block is GOOD, I should probably label each line individually.

This is a very odd thing to do, I'm preparing a statement that contains a parameter (the ? on line 81), binding values to the parameter three times over, then running it six times with new bindings on the parameter each time. The point is simply to check that none of the 9 operations that bind values are flagged even with a tainted value - because binding values to parameters is the 'safe' way to pass tainted data into an SQL statement.

@jketema
Copy link
Contributor

jketema commented Oct 18, 2022

Does this still need a doc review?

@geoffw0
Copy link
Contributor Author

geoffw0 commented Oct 18, 2022

Oh, good point!

@geoffw0 geoffw0 added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Oct 18, 2022
Copy link
Contributor

@jketema jketema left a comment

I'm happy with the current version, so just waiting for the doc review.

Copy link
Contributor

@subatoi subatoi left a comment

Hi there @geoffw0, I'm the first responder for the Docs team this week so I've taken a look at this and left some small comments and asked a couple of minor questions. I hope this isn't adding too much overhead 🙏

I'll just tag my colleague @felicitymay as well just in case (might not be necessary but I'm still quite new to reviewing CodeQL! 😁 )

swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp Outdated Show resolved Hide resolved
swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp Outdated Show resolved Hide resolved
swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp Outdated Show resolved Hide resolved
swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp Outdated Show resolved Hide resolved
swift/ql/src/queries/Security/CWE-089/SqlInjection.qhelp Outdated Show resolved Hide resolved
@geoffw0
Copy link
Contributor Author

geoffw0 commented Oct 19, 2022

Thanks for the review @subatoi . I believe I've addressed all your points, but please don't hesitate to say if you think it needs more work.

subatoi
subatoi previously approved these changes Oct 20, 2022
Copy link
Contributor

@subatoi subatoi left a comment

Just added a couple of minor last points to make the language a bit simpler. There's nothing wrong with the existing language; these suggestions are just minor and style-related. Otherwise approving and LGTM. Thank you!

Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com>
@geoffw0
Copy link
Contributor Author

geoffw0 commented Oct 20, 2022

Thanks - those suggestions definitely help make things read a bit more easily. Please approve the PR if you're happy with the docs now (the code has already been reviewed and approved).

Copy link
Contributor

@subatoi subatoi left a comment

Thanks @geoffw0, apologies, didn't realise my review would be dismissed. LGTM!

@geoffw0
Copy link
Contributor Author

geoffw0 commented Oct 20, 2022

Yep, whenever a change is pushed all reviews of the existing code are dismissed automatically. It makes sense but it can be a bit much sometimes (especially when the change is just accepting a suggestion from the approver!)

@geoffw0 geoffw0 merged commit 1386435 into github:main Oct 20, 2022
13 checks passed
@geoffw0
Copy link
Contributor Author

geoffw0 commented Oct 20, 2022

Thanks again for the review, suggestions and approval. On to the next query!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation no-change-note-required This PR does not need a change note ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. Swift
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants