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: Add AEXML sinks to XXE query #11138

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

atorralba
Copy link
Contributor

@atorralba atorralba commented Nov 7, 2022

Note this is built on top of #11086 and #11120 until those are merged (at which time this will rebased). If you want to review early, look at commit bbf7bb3 only (and potentially any other commit after that).

The caveat of these sinks is that they heavily rely on local data flow, and because of that we might have some FNs when tracking the unsafe option all the way to the actual sink requires global data flow instead.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 7, 2022

QHelp previews:

swift/ql/src/queries/Security/CWE-611/XXE.qhelp

Resolving XML external entity in user-controlled data

Parsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial of service, or server side request forgery. Even when the result of parsing is not returned to the user, out-of-band data retrieval techniques may allow attackers to steal sensitive data. Denial of services can also be carried out in this situation.

Recommendation

The easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of XMLParser, disable entity expansion by default, so unless you have explicitly enabled entity expansion, no further action needs to be taken.

Example

The following example uses the XMLParser class to parse a string data. If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since the parser is also setting its shouldResolveExternalEntities option to true:

let parser = XMLParser(data: remoteData) // BAD (parser explicitly enables external entities)
parser.shouldResolveExternalEntities = true

To guard against XXE attacks, the shouldResolveExternalEntities option should be left unset or explicitly set to false.

let parser = XMLParser(data: remoteData) // GOOD (parser explicitly disables external entities)
parser.shouldResolveExternalEntities = false

References


/** An expression of type `AEXMLOptions.ParserSettings`. */
class ParserSettings extends Expr {
pragma[inline]
Copy link
Contributor Author

@atorralba atorralba Nov 7, 2022

Choose a reason for hiding this comment

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

These two pragma[inline]s are an attempt at avoiding fully computing these classes, which seemed to be potentially too big depending on the codebase. Hopefully inlining them where they are used should add the appropriate context to prevent it, while allowing us to reuse this code, but please let me know if this solution is not desirable performance-wise and/or there's a better alternative. I'll launch DCA in any case to see how this behaves.

Copy link
Contributor

@geoffw0 geoffw0 Nov 7, 2022

Choose a reason for hiding this comment

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

Yep, I agree we should do a DCA run to check how this does. Though I'm not overly concerned about Swift query performance - I think it will be more effective to do a review later on (when we have a full query suite and thus better data).

@atorralba atorralba force-pushed the atorralba/swift/xxe-query-aexml-sinks branch from 0ae7e52 to bbf7bb3 Compare Nov 7, 2022
Copy link
Contributor

@geoffw0 geoffw0 left a comment

Looks like a good addition. 👍

class AEXMLDocument {
init(root: AEXMLElement? = nil, options: AEXMLOptions) {}
init(xml: Data, options: AEXMLOptions = AEXMLOptions()) {}
init(xml: String, encoding: String.Encoding, options: AEXMLOptions) {}
Copy link
Contributor

@geoffw0 geoffw0 Nov 7, 2022

Choose a reason for hiding this comment

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

The AEXML library itself has some defaults you don't specify here. Your test cases below obviously don't use them. Can you imagine it matters?

Copy link
Contributor Author

@atorralba atorralba Nov 7, 2022

Choose a reason for hiding this comment

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

The empty AEXMLOptions and String.Encoding = utf8 would hardly affect the results. At most, we could verify that we correctly have TNs when the default options: argument is used, but the test would look very similar to the ones explicitly setting an empty AEXMLOptions (i.e. the *safeImplicit test cases). I'm open to adding those additional cases nevertheless, if you think they are worth it.

Copy link
Contributor Author

@atorralba atorralba Nov 7, 2022

Choose a reason for hiding this comment

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

But if we decide not to, I could completely remove all defaults from the stubs, so that we are consistent and avoid potential confusion.

Copy link
Contributor

@geoffw0 geoffw0 Nov 7, 2022

Choose a reason for hiding this comment

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

I'm happy how it is. But I have wondered when implementing tests myself whether I should put effort into modelling and using default values accurately to how the libraries do it. I think you're right there isn't much difference between using a default and using a non-default value that's the same as it anyway. The query certainly doesn't care if a default is there / used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants