-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Swift: Query for Use of an inappropriate cryptographic hashing algorithm on passwords #15122
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
Merged
Merged
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
be7d0ac
Swift: Minor fixes for the existing weak sensitive data hashing query…
geoffw0 9774c3c
Swift: Copy WeakPasswordHashing query from csharp.
geoffw0 db1508d
Swift: Trivial changes - query ID / metadata, imports.
geoffw0 e5bf929
Swift: Split off WeakPasswordHashingExtensions.qll as we normally do.
geoffw0 b5a45c6
Swift: Define barriers, additional flow steps and sinks.
geoffw0 5faa25f
Swift: Make passwords their own sensitive data type.
geoffw0 10b4c98
Swift: Move password sources to be reported by the new query.
geoffw0 22ed20d
Swift: Upgrade SecKeyCopyExternalRepresentation source to be consider…
geoffw0 87eb96e
Swift: Add more cases to test.
geoffw0 c2d49c0
Swift: Address a weakness in the sensitive data regexs.
geoffw0 7ba18e6
Swift: Add sinks for algorithms that are OK for sensitive data hashin…
geoffw0 3a900f1
Swift: Fix some inconsistencies in the test cases.
geoffw0 9ec08c1
Swift: Add a couple of sinks missing from sensitive data hashing as w…
geoffw0 363ec0a
Swift: Update swift/summary/query-sinks.
geoffw0 0ff84b4
Swift: Create examples for the .qhelp in Swift, and test them.
geoffw0 b7a533f
Swift: Update .qhelp for Swift.
geoffw0 326242a
Swift: Change note.
geoffw0 034daa9
Swift: Address false positives.
geoffw0 0b04e4a
Swift: Address QL-for-QL alerts.
geoffw0 f6a4970
Swift: Autoformat.
geoffw0 2ab5e6f
Swift: Add link / reference to CryptoSwift.
geoffw0 657e4d4
Apply suggestions from code review
geoffw0 80afa65
Swift: Add GOOD and BAD comments.
geoffw0 a0ea714
Swift: Add GOOD and BAD comments in the sensitive data hashing exampl…
geoffw0 0aec2b1
Swift: Improve consistency of phrasing arouaround 'computationally ha…
geoffw0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
swift/ql/lib/codeql/swift/security/WeakPasswordHashingExtensions.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| /** | ||
| * Provides classes and predicates for reasoning about use of inappropriate | ||
| * cryptographic hashing algorithms on passwords. | ||
| */ | ||
|
|
||
| import swift | ||
| import codeql.swift.dataflow.DataFlow | ||
| import codeql.swift.dataflow.ExternalFlow | ||
| private import codeql.swift.security.WeakSensitiveDataHashingExtensions | ||
|
|
||
| /** | ||
| * A dataflow sink for weak password hashing vulnerabilities. That is, | ||
| * a `DataFlow::Node` that is passed into a weak password hashing function. | ||
| */ | ||
| abstract class WeakPasswordHashingSink extends DataFlow::Node { | ||
| /** | ||
| * Gets the name of the hashing algorithm, for display. | ||
| */ | ||
| abstract string getAlgorithm(); | ||
| } | ||
|
|
||
| /** | ||
| * A barrier for weak password hashing vulnerabilities. | ||
| */ | ||
| abstract class WeakPasswordHashingBarrier extends DataFlow::Node { } | ||
|
|
||
| /** | ||
| * A unit class for adding additional flow steps. | ||
| */ | ||
| class WeakPasswordHashingAdditionalFlowStep extends Unit { | ||
| /** | ||
| * Holds if the step from `node1` to `node2` should be considered a flow | ||
| * step for paths related to weak password hashing vulnerabilities. | ||
| */ | ||
| abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo); | ||
| } | ||
|
|
||
| /** | ||
| * A sink inherited from weak sensitive data hashing. Password hashing has | ||
| * stronger requirements than sensitive data hashing, since (in addition to | ||
| * its particular qualities) a password *is* sensitive data. Thus, any sink | ||
| * for the weak sensitive data hashing query is a sink for weak password | ||
| * hashing as well. | ||
| */ | ||
| private class InheritedWeakPasswordHashingSink extends WeakPasswordHashingSink { | ||
| InheritedWeakPasswordHashingSink() { this instanceof WeakSensitiveDataHashingSink } | ||
|
|
||
| override string getAlgorithm() { result = this.(WeakSensitiveDataHashingSink).getAlgorithm() } | ||
| } | ||
|
|
||
| private class WeakSensitiveDataHashingSinks extends SinkModelCsv { | ||
| override predicate row(string row) { | ||
| row = | ||
| [ | ||
| // CryptoKit | ||
| // (SHA-256, SHA-384 and SHA-512 are all variants of the SHA-2 algorithm) | ||
| ";SHA256;true;hash(data:);;;Argument[0];weak-password-hash-input-SHA256", | ||
| ";SHA256;true;update(data:);;;Argument[0];weak-password-hash-input-SHA256", | ||
| ";SHA256;true;update(bufferPointer:);;;Argument[0];weak-password-hash-input-SHA256", | ||
| ";SHA384;true;hash(data:);;;Argument[0];weak-password-hash-input-SHA384", | ||
| ";SHA384;true;update(data:);;;Argument[0];weak-password-hash-input-SHA384", | ||
| ";SHA384;true;update(bufferPointer:);;;Argument[0];weak-password-hash-input-SHA384", | ||
| ";SHA512;true;hash(data:);;;Argument[0];weak-password-hash-input-SHA512", | ||
| ";SHA512;true;update(data:);;;Argument[0];weak-password-hash-input-SHA512", | ||
| ";SHA512;true;update(bufferPointer:);;;Argument[0];weak-password-hash-input-SHA512", | ||
| // CryptoSwift | ||
| ";SHA2;true;calculate(for:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";SHA2;true;callAsFunction(_:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";SHA2;true;process64(block:currentHash:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";SHA2;true;process32(block:currentHash:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";SHA2;true;update(withBytes:isLast:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";SHA3;true;calculate(for:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";SHA3;true;callAsFunction(_:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";SHA3;true;process(block:currentHash:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";SHA3;true;update(withBytes:isLast:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";Digest;true;sha2(_:variant:);;;Argument[0];weak-password-hash-input-SHA2", | ||
| ";Digest;true;sha3(_:variant:);;;Argument[0];weak-password-hash-input-SHA3", | ||
| ";Digest;true;sha224(_:);;;Argument[0];weak-password-hash-input-SHA224", | ||
| ";Digest;true;sha256(_:);;;Argument[0];weak-password-hash-input-SHA256", | ||
| ";Digest;true;sha384(_:);;;Argument[0];weak-password-hash-input-SHA384", | ||
| ";Digest;true;sha512(_:);;;Argument[0];weak-password-hash-input-SHA512", | ||
| ";Array;true;sha2(_:);;;Argument[-1];weak-password-hash-input-SHA2", | ||
| ";Array;true;sha3(_:);;;Argument[-1];weak-password-hash-input-SHA3", | ||
| ";Array;true;sha224();;;Argument[-1];weak-password-hash-input-SHA224", | ||
| ";Array;true;sha256();;;Argument[-1];weak-password-hash-input-SHA256", | ||
| ";Array;true;sha384();;;Argument[-1];weak-password-hash-input-SHA384", | ||
| ";Array;true;sha512();;;Argument[-1];weak-password-hash-input-SHA512", | ||
| ";Data;true;sha2(_:);;;Argument[-1];weak-password-hash-input-SHA2", | ||
| ";Data;true;sha3(_:);;;Argument[-1];weak-password-hash-input-SHA3", | ||
| ";Data;true;sha224();;;Argument[-1];weak-password-hash-input-SHA224", | ||
| ";Data;true;sha256();;;Argument[-1];weak-password-hash-input-SHA256", | ||
| ";Data;true;sha384();;;Argument[-1];weak-password-hash-input-SHA384", | ||
| ";Data;true;sha512();;;Argument[-1];weak-password-hash-input-SHA512", | ||
| ";String;true;sha2(_:);;;Argument[-1];weak-password-hash-input-SHA2", | ||
| ";String;true;sha3(_:);;;Argument[-1];weak-password-hash-input-SHA3", | ||
| ";String;true;sha224();;;Argument[-1];weak-password-hash-input-SHA224", | ||
| ";String;true;sha256();;;Argument[-1];weak-password-hash-input-SHA256", | ||
| ";String;true;sha384();;;Argument[-1];weak-password-hash-input-SHA384", | ||
| ";String;true;sha512();;;Argument[-1];weak-password-hash-input-SHA512", | ||
| ] | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * A sink defined in a CSV model. | ||
| */ | ||
| private class DefaultWeakPasswordHashingSink extends WeakPasswordHashingSink { | ||
| string algorithm; | ||
|
|
||
| DefaultWeakPasswordHashingSink() { sinkNode(this, "weak-password-hash-input-" + algorithm) } | ||
|
|
||
| override string getAlgorithm() { result = algorithm } | ||
| } | ||
43 changes: 43 additions & 0 deletions
43
swift/ql/lib/codeql/swift/security/WeakPasswordHashingQuery.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| /** | ||
| * Provides a taint tracking configuration to find use of inappropriate | ||
| * cryptographic hashing algorithms on passwords. | ||
| */ | ||
|
|
||
| import swift | ||
| import codeql.swift.security.SensitiveExprs | ||
| import codeql.swift.dataflow.DataFlow | ||
|
||
| import codeql.swift.dataflow.TaintTracking | ||
| import codeql.swift.security.WeakPasswordHashingExtensions | ||
|
|
||
| /** | ||
| * A taint tracking configuration from password expressions to inappropriate | ||
| * hashing sinks. | ||
| */ | ||
| module WeakPasswordHashingConfig implements DataFlow::ConfigSig { | ||
| predicate isSource(DataFlow::Node node) { | ||
| exists(SensitiveExpr se | | ||
| node.asExpr() = se and | ||
| se.getSensitiveType() instanceof SensitivePassword | ||
| ) | ||
| } | ||
|
|
||
| predicate isSink(DataFlow::Node node) { node instanceof WeakPasswordHashingSink } | ||
|
|
||
| predicate isBarrier(DataFlow::Node node) { node instanceof WeakPasswordHashingBarrier } | ||
|
|
||
| predicate isBarrierIn(DataFlow::Node node) { | ||
| // make sources barriers so that we only report the closest instance | ||
| isSource(node) | ||
| } | ||
|
|
||
| predicate isBarrierOut(DataFlow::Node node) { | ||
| // make sinks barriers so that we only report the closest instance | ||
| isSink(node) | ||
| } | ||
|
|
||
| predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { | ||
| any(WeakPasswordHashingAdditionalFlowStep s).step(nodeFrom, nodeTo) | ||
| } | ||
| } | ||
|
|
||
| module WeakPasswordHashingFlow = TaintTracking::Global<WeakPasswordHashingConfig>; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
swift/ql/src/queries/Security/CWE-328/WeakPasswordHashing.qhelp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
| <overview> | ||
| <p> | ||
| Using a insufficiently computationally hard hash function can leave data | ||
| vulnerable, and should not be used for password hashing. | ||
| </p> | ||
geoffw0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| <p> | ||
| A strong cryptographic hash function should be resistant to: | ||
| </p> | ||
| <ul> | ||
| <li> | ||
| <strong>Pre-image attacks</strong>. If you know a hash value <code>h(x)</code>, | ||
| you should not be able to easily find the input <code>x</code>. | ||
| </li> | ||
| <li> | ||
| <strong>Collision attacks</strong>. If you know a hash value <code>h(x)</code>, | ||
| you should not be able to easily find a different input | ||
| <code>y</code> | ||
| with the same hash value <code>h(x) = h(y)</code>. | ||
| </li> | ||
| <li> | ||
| <strong>Brute force</strong>. If you know a hash value <code>h(x)</code>, | ||
| you should not be able to find an input <code>y</code> that computes to that hash value | ||
| using brute force attacks without significant computational effort. | ||
| <li> | ||
| </ul> | ||
|
|
||
| <p> | ||
| All of MD5, SHA-1, SHA-2 and SHA-3 are weak against offline brute forcing, since they are not computationally hard. This includes SHA-224, SHA-256, SHA-384 and SHA-512, which are in the SHA-2 family. | ||
| </p> | ||
|
|
||
| <p> | ||
| Password hashing algorithms are designed to be slow and/or memory intenstive to compute, which makes brute force attacks more difficult. | ||
| </p> | ||
geoffw0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| </overview> | ||
| <recommendation> | ||
|
|
||
| <p> | ||
| Ensure that for password storage you should use a computationally hard cryptographic hash function, such as: | ||
| </p> | ||
geoffw0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| <ul> | ||
| <li> | ||
| Argon2 | ||
| </li> | ||
| <li> | ||
| scrypt | ||
| </li> | ||
| <li> | ||
| bcrypt | ||
| </li> | ||
| <li> | ||
| PBKDF2 | ||
| </li> | ||
| </ul> | ||
|
|
||
| </recommendation> | ||
| <example> | ||
|
|
||
| <p> | ||
| The following examples show a function that hashes a password using a cryptographic hashing algorithm. | ||
|
|
||
| In the first case the SHA-512 hashing algorithm is used. It is vulnerable to offline brute force attacks: | ||
| </p> | ||
geoffw0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| <sample src="WeakPasswordHashingBad.swift"/> | ||
| <p> | ||
|
|
||
| Here is the same function using Argon2, which is suitable for password hashing: | ||
| </p> | ||
| <sample src="WeakPasswordHashingGood.swift"/> | ||
|
|
||
| </example> | ||
| <references> | ||
| <li> | ||
| OWASP: | ||
| <a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html">Password Storage | ||
| Cheat Sheet | ||
| </a> | ||
| </li> | ||
| <li> | ||
| libsodium: <a href="https://doc.libsodium.org/bindings_for_other_languages#bindings-programming-languages">libsodium bindings for other languages</a> | ||
| </li> | ||
| <li> | ||
| GitHub: <a href="https://github.com/tmthecoder/Argon2Swift">Argon2Swift</a> | ||
| </li> | ||
| </references> | ||
|
|
||
| </qhelp> | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.