mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #20432 from github/copilot/fix-f50317f8-0a91-4bb4-a01b-353dcf0f6f3f
Rust: Implement new query for non-HTTPS URLs (CWE-319)
This commit is contained in:
@@ -14,6 +14,7 @@ ql/rust/ql/src/queries/security/CWE-089/SqlInjection.ql
|
||||
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
|
||||
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
|
||||
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql
|
||||
ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql
|
||||
ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql
|
||||
ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql
|
||||
ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
|
||||
|
||||
@@ -15,6 +15,7 @@ ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql
|
||||
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
|
||||
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
|
||||
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql
|
||||
ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql
|
||||
ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql
|
||||
ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql
|
||||
ql/rust/ql/src/queries/security/CWE-696/BadCtorInitialization.ql
|
||||
|
||||
@@ -15,6 +15,7 @@ ql/rust/ql/src/queries/security/CWE-117/LogInjection.ql
|
||||
ql/rust/ql/src/queries/security/CWE-311/CleartextTransmission.ql
|
||||
ql/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
|
||||
ql/rust/ql/src/queries/security/CWE-312/CleartextStorageDatabase.ql
|
||||
ql/rust/ql/src/queries/security/CWE-319/UseOfHttp.ql
|
||||
ql/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql
|
||||
ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql
|
||||
ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
|
||||
|
||||
62
rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll
Normal file
62
rust/ql/lib/codeql/rust/security/UseOfHttpExtensions.qll
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Provides classes and predicates for reasoning about the use of
|
||||
* non-HTTPS URLs in Rust code.
|
||||
*/
|
||||
|
||||
import rust
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.dataflow.FlowSink
|
||||
private import codeql.rust.Concepts
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and barriers for detecting use of
|
||||
* non-HTTPS URLs, as well as extension points for adding your own.
|
||||
*/
|
||||
module UseOfHttp {
|
||||
/**
|
||||
* A data flow source for use of non-HTTPS URLs.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for use of non-HTTPS URLs.
|
||||
*/
|
||||
abstract class Sink extends QuerySink::Range {
|
||||
override string getSinkType() { result = "UseOfHttp" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A barrier for use of non-HTTPS URLs.
|
||||
*/
|
||||
abstract class Barrier extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A string containing an HTTP URL.
|
||||
*/
|
||||
class HttpStringLiteral extends StringLiteralExpr {
|
||||
HttpStringLiteral() {
|
||||
exists(string s | this.getTextValue() = s |
|
||||
// match HTTP URLs
|
||||
s.regexpMatch("(?i)\"http://.*\"") and
|
||||
// exclude private/local addresses:
|
||||
// - IPv4: localhost / 127.0.0.1, 192.168.x.x, 10.x.x.x, 172.16.x.x -> 172.31.x.x
|
||||
// - IPv6 (address inside []): ::1 (or 0:0:0:0:0:0:0:1), fc00::/7 (i.e. anything beginning `fcxx:` or `fdxx:`)
|
||||
not s.regexpMatch("(?i)\"http://(localhost|127\\.0\\.0\\.1|192\\.168\\.[0-9]+\\.[0-9]+|10\\.[0-9]+\\.[0-9]+\\.[0-9]+|172\\.(1[6-9]|2[0-9]|3[01])\\.[0-9]+|\\[::1\\]|\\[0:0:0:0:0:0:0:1\\]|\\[f[cd][0-9a-f]{2}:.*\\]).*\"")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An HTTP string literal as a source.
|
||||
*/
|
||||
private class HttpStringLiteralAsSource extends Source {
|
||||
HttpStringLiteralAsSource() { this.asExpr().getExpr() instanceof HttpStringLiteral }
|
||||
}
|
||||
|
||||
/**
|
||||
* A sink for use of HTTP URLs from model data.
|
||||
*/
|
||||
private class ModelsAsDataSink extends Sink {
|
||||
ModelsAsDataSink() { sinkNode(this, "request-url") }
|
||||
}
|
||||
}
|
||||
4
rust/ql/src/change-notes/2025-09-15-non-https-url.md
Normal file
4
rust/ql/src/change-notes/2025-09-15-non-https-url.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `rust/non-https-url`, for detecting the use of non-HTTPS URLs that can be intercepted by third parties.
|
||||
49
rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp
Normal file
49
rust/ql/src/queries/security/CWE-319/UseOfHttp.qhelp
Normal file
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
|
||||
<p>Constructing URLs with the HTTP protocol can lead to insecure connections.</p>
|
||||
|
||||
<p>Furthermore, constructing URLs with the HTTP protocol can create problems if other parts of the
|
||||
code expect HTTPS URLs. A typical pattern is to use libraries that expect secure connections,
|
||||
which may fail or fall back to insecure behavior when provided with HTTP URLs instead of HTTPS URLs.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>When you construct a URL for network requests, ensure that you use an HTTPS URL rather than an HTTP URL.
|
||||
Then, any connections that are made using that URL are secure TLS connections.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>The following examples show two ways of making a network request using a URL. When the request is
|
||||
made using an HTTP URL rather than an HTTPS URL, the connection is unsecured and can be intercepted
|
||||
by attackers:</p>
|
||||
|
||||
<sample src="UseOfHttpBad.rs" />
|
||||
|
||||
<p>A better approach is to use HTTPS. When the request is made using an HTTPS URL, the connection
|
||||
is a secure TLS connection:</p>
|
||||
|
||||
<sample src="UseOfHttpGood.rs" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html">Transport Layer Security Cheat Sheet</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP Top 10:
|
||||
<a href="https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/">A08:2021 - Software and Data Integrity Failures</a>.
|
||||
</li>
|
||||
<li>Rust reqwest documentation:
|
||||
<a href="https://docs.rs/reqwest/">reqwest crate</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
42
rust/ql/src/queries/security/CWE-319/UseOfHttp.ql
Normal file
42
rust/ql/src/queries/security/CWE-319/UseOfHttp.ql
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @name Failure to use HTTPS URLs
|
||||
* @description Non-HTTPS connections can be intercepted by third parties.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.1
|
||||
* @precision high
|
||||
* @id rust/non-https-url
|
||||
* @tags security
|
||||
* external/cwe/cwe-319
|
||||
* external/cwe/cwe-345
|
||||
*/
|
||||
|
||||
import rust
|
||||
import codeql.rust.dataflow.DataFlow
|
||||
import codeql.rust.dataflow.TaintTracking
|
||||
import codeql.rust.security.UseOfHttpExtensions
|
||||
|
||||
/**
|
||||
* A taint configuration for HTTP URL strings that flow to URL-using sinks.
|
||||
*/
|
||||
module UseOfHttpConfig implements DataFlow::ConfigSig {
|
||||
import UseOfHttp
|
||||
|
||||
predicate isSource(DataFlow::Node node) { node instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node node) { node instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
module UseOfHttpFlow = TaintTracking::Global<UseOfHttpConfig>;
|
||||
|
||||
import UseOfHttpFlow::PathGraph
|
||||
|
||||
from UseOfHttpFlow::PathNode sourceNode, UseOfHttpFlow::PathNode sinkNode
|
||||
where UseOfHttpFlow::flowPath(sourceNode, sinkNode)
|
||||
select sinkNode.getNode(), sourceNode, sinkNode,
|
||||
"This URL may be constructed with the HTTP protocol, from $@.", sourceNode.getNode(),
|
||||
"this HTTP URL"
|
||||
10
rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs
Normal file
10
rust/ql/src/queries/security/CWE-319/UseOfHttpBad.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
// BAD: Using HTTP URL which can be intercepted
|
||||
use reqwest;
|
||||
|
||||
fn main() {
|
||||
let url = "http://example.com/sensitive-data";
|
||||
|
||||
// This makes an insecure HTTP request that can be intercepted
|
||||
let response = reqwest::blocking::get(url).unwrap();
|
||||
println!("Response: {}", response.text().unwrap());
|
||||
}
|
||||
10
rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs
Normal file
10
rust/ql/src/queries/security/CWE-319/UseOfHttpGood.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
// GOOD: Using HTTPS URL which provides encryption
|
||||
use reqwest;
|
||||
|
||||
fn main() {
|
||||
let url = "https://example.com/sensitive-data";
|
||||
|
||||
// This makes a secure HTTPS request that is encrypted
|
||||
let response = reqwest::blocking::get(url).unwrap();
|
||||
println!("Response: {}", response.text().unwrap());
|
||||
}
|
||||
@@ -27,6 +27,7 @@ private import codeql.rust.security.LogInjectionExtensions
|
||||
private import codeql.rust.security.SqlInjectionExtensions
|
||||
private import codeql.rust.security.TaintedPathExtensions
|
||||
private import codeql.rust.security.UncontrolledAllocationSizeExtensions
|
||||
private import codeql.rust.security.UseOfHttpExtensions
|
||||
private import codeql.rust.security.WeakSensitiveDataHashingExtensions
|
||||
private import codeql.rust.security.HardcodedCryptographicValueExtensions
|
||||
|
||||
|
||||
1574
rust/ql/test/query-tests/security/CWE-319/Cargo.lock
generated
Normal file
1574
rust/ql/test/query-tests/security/CWE-319/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
76
rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected
Normal file
76
rust/ql/test/query-tests/security/CWE-319/UseOfHttp.expected
Normal file
@@ -0,0 +1,76 @@
|
||||
#select
|
||||
| main.rs:12:22:12:43 | ...::get | main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:12:45:12:68 | "http://example.com/api" | this HTTP URL |
|
||||
| main.rs:13:22:13:43 | ...::get | main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | main.rs:13:22:13:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | this HTTP URL |
|
||||
| main.rs:14:22:14:43 | ...::get | main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:14:45:14:73 | "http://api.example.com/data" | this HTTP URL |
|
||||
| main.rs:26:21:26:42 | ...::get | main.rs:23:20:23:39 | "http://example.com" | main.rs:26:21:26:42 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:23:20:23:39 | "http://example.com" | this HTTP URL |
|
||||
| main.rs:37:30:37:51 | ...::get | main.rs:34:20:34:28 | "http://" | main.rs:37:30:37:51 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:34:20:34:28 | "http://" | this HTTP URL |
|
||||
| main.rs:60:20:60:41 | ...::get | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:60:43:60:65 | "http://172.32.0.0/baz" | this HTTP URL |
|
||||
| main.rs:71:24:71:45 | ...::get | main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:71:24:71:45 | ...::get | This URL may be constructed with the HTTP protocol, from $@. | main.rs:68:19:68:53 | "http://example.com/sensitive-... | this HTTP URL |
|
||||
edges
|
||||
| main.rs:12:45:12:68 | "http://example.com/api" | main.rs:12:22:12:43 | ...::get | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | main.rs:13:22:13:43 | ...::get | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:14:45:14:73 | "http://api.example.com/data" | main.rs:14:22:14:43 | ...::get | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:23:9:23:16 | base_url | main.rs:25:28:25:53 | MacroExpr | provenance | |
|
||||
| main.rs:23:20:23:39 | "http://example.com" | main.rs:23:9:23:16 | base_url | provenance | |
|
||||
| main.rs:25:9:25:16 | full_url | main.rs:26:45:26:52 | full_url | provenance | |
|
||||
| main.rs:25:20:25:26 | res | main.rs:25:28:25:53 | { ... } | provenance | |
|
||||
| main.rs:25:28:25:53 | ...::format(...) | main.rs:25:20:25:26 | res | provenance | |
|
||||
| main.rs:25:28:25:53 | ...::must_use(...) | main.rs:25:9:25:16 | full_url | provenance | |
|
||||
| main.rs:25:28:25:53 | MacroExpr | main.rs:25:28:25:53 | ...::format(...) | provenance | MaD:2 |
|
||||
| main.rs:25:28:25:53 | { ... } | main.rs:25:28:25:53 | ...::must_use(...) | provenance | MaD:3 |
|
||||
| main.rs:26:44:26:52 | &full_url [&ref] | main.rs:26:21:26:42 | ...::get | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:26:45:26:52 | full_url | main.rs:26:44:26:52 | &full_url [&ref] | provenance | |
|
||||
| main.rs:34:9:34:16 | protocol | main.rs:36:32:36:53 | MacroExpr | provenance | |
|
||||
| main.rs:34:20:34:28 | "http://" | main.rs:34:9:34:16 | protocol | provenance | |
|
||||
| main.rs:36:9:36:20 | insecure_url | main.rs:37:54:37:65 | insecure_url | provenance | |
|
||||
| main.rs:36:24:36:30 | res | main.rs:36:32:36:53 | { ... } | provenance | |
|
||||
| main.rs:36:32:36:53 | ...::format(...) | main.rs:36:24:36:30 | res | provenance | |
|
||||
| main.rs:36:32:36:53 | ...::must_use(...) | main.rs:36:9:36:20 | insecure_url | provenance | |
|
||||
| main.rs:36:32:36:53 | MacroExpr | main.rs:36:32:36:53 | ...::format(...) | provenance | MaD:2 |
|
||||
| main.rs:36:32:36:53 | { ... } | main.rs:36:32:36:53 | ...::must_use(...) | provenance | MaD:3 |
|
||||
| main.rs:37:53:37:65 | &insecure_url [&ref] | main.rs:37:30:37:51 | ...::get | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:37:54:37:65 | insecure_url | main.rs:37:53:37:65 | &insecure_url [&ref] | provenance | |
|
||||
| main.rs:60:43:60:65 | "http://172.32.0.0/baz" | main.rs:60:20:60:41 | ...::get | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:68:13:68:15 | url | main.rs:71:47:71:49 | url | provenance | |
|
||||
| main.rs:68:19:68:53 | "http://example.com/sensitive-... | main.rs:68:13:68:15 | url | provenance | |
|
||||
| main.rs:71:47:71:49 | url | main.rs:71:24:71:45 | ...::get | provenance | MaD:1 Sink:MaD:1 |
|
||||
models
|
||||
| 1 | Sink: reqwest::blocking::get; Argument[0]; request-url |
|
||||
| 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
|
||||
| 3 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
|
||||
nodes
|
||||
| main.rs:12:22:12:43 | ...::get | semmle.label | ...::get |
|
||||
| main.rs:12:45:12:68 | "http://example.com/api" | semmle.label | "http://example.com/api" |
|
||||
| main.rs:13:22:13:43 | ...::get | semmle.label | ...::get |
|
||||
| main.rs:13:45:13:68 | "HTTP://EXAMPLE.COM/API" | semmle.label | "HTTP://EXAMPLE.COM/API" |
|
||||
| main.rs:14:22:14:43 | ...::get | semmle.label | ...::get |
|
||||
| main.rs:14:45:14:73 | "http://api.example.com/data" | semmle.label | "http://api.example.com/data" |
|
||||
| main.rs:23:9:23:16 | base_url | semmle.label | base_url |
|
||||
| main.rs:23:20:23:39 | "http://example.com" | semmle.label | "http://example.com" |
|
||||
| main.rs:25:9:25:16 | full_url | semmle.label | full_url |
|
||||
| main.rs:25:20:25:26 | res | semmle.label | res |
|
||||
| main.rs:25:28:25:53 | ...::format(...) | semmle.label | ...::format(...) |
|
||||
| main.rs:25:28:25:53 | ...::must_use(...) | semmle.label | ...::must_use(...) |
|
||||
| main.rs:25:28:25:53 | MacroExpr | semmle.label | MacroExpr |
|
||||
| main.rs:25:28:25:53 | { ... } | semmle.label | { ... } |
|
||||
| main.rs:26:21:26:42 | ...::get | semmle.label | ...::get |
|
||||
| main.rs:26:44:26:52 | &full_url [&ref] | semmle.label | &full_url [&ref] |
|
||||
| main.rs:26:45:26:52 | full_url | semmle.label | full_url |
|
||||
| main.rs:34:9:34:16 | protocol | semmle.label | protocol |
|
||||
| main.rs:34:20:34:28 | "http://" | semmle.label | "http://" |
|
||||
| main.rs:36:9:36:20 | insecure_url | semmle.label | insecure_url |
|
||||
| main.rs:36:24:36:30 | res | semmle.label | res |
|
||||
| main.rs:36:32:36:53 | ...::format(...) | semmle.label | ...::format(...) |
|
||||
| main.rs:36:32:36:53 | ...::must_use(...) | semmle.label | ...::must_use(...) |
|
||||
| main.rs:36:32:36:53 | MacroExpr | semmle.label | MacroExpr |
|
||||
| main.rs:36:32:36:53 | { ... } | semmle.label | { ... } |
|
||||
| main.rs:37:30:37:51 | ...::get | semmle.label | ...::get |
|
||||
| main.rs:37:53:37:65 | &insecure_url [&ref] | semmle.label | &insecure_url [&ref] |
|
||||
| main.rs:37:54:37:65 | insecure_url | semmle.label | insecure_url |
|
||||
| main.rs:60:20:60:41 | ...::get | semmle.label | ...::get |
|
||||
| main.rs:60:43:60:65 | "http://172.32.0.0/baz" | semmle.label | "http://172.32.0.0/baz" |
|
||||
| main.rs:68:13:68:15 | url | semmle.label | url |
|
||||
| main.rs:68:19:68:53 | "http://example.com/sensitive-... | semmle.label | "http://example.com/sensitive-... |
|
||||
| main.rs:71:24:71:45 | ...::get | semmle.label | ...::get |
|
||||
| main.rs:71:47:71:49 | url | semmle.label | url |
|
||||
subpaths
|
||||
@@ -0,0 +1,4 @@
|
||||
query: queries/security/CWE-319/UseOfHttp.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
83
rust/ql/test/query-tests/security/CWE-319/main.rs
Normal file
83
rust/ql/test/query-tests/security/CWE-319/main.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use reqwest;
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
test_direct_literals();
|
||||
test_dynamic_urls();
|
||||
test_localhost_exemptions();
|
||||
}
|
||||
|
||||
fn test_direct_literals() {
|
||||
// BAD: Direct HTTP URLs that should be flagged
|
||||
let _response1 = reqwest::blocking::get("http://example.com/api").unwrap(); // $ Alert[rust/non-https-url]
|
||||
let _response2 = reqwest::blocking::get("HTTP://EXAMPLE.COM/API").unwrap(); // $ Alert[rust/non-https-url]
|
||||
let _response3 = reqwest::blocking::get("http://api.example.com/data").unwrap(); // $ Alert[rust/non-https-url]
|
||||
|
||||
// GOOD: HTTPS URLs that should not be flagged
|
||||
let _response3 = reqwest::blocking::get("https://example.com/api").unwrap();
|
||||
let _response4 = reqwest::blocking::get("https://api.example.com/data").unwrap();
|
||||
}
|
||||
|
||||
fn test_dynamic_urls() {
|
||||
// BAD: HTTP URLs constructed dynamically
|
||||
let base_url = "http://example.com"; // $ Source
|
||||
let endpoint = "/api/users";
|
||||
let full_url = format!("{}{}", base_url, endpoint);
|
||||
let _response = reqwest::blocking::get(&full_url).unwrap(); // $ Alert[rust/non-https-url]
|
||||
|
||||
// GOOD: HTTPS URLs constructed dynamically
|
||||
let secure_base = "https://example.com";
|
||||
let secure_full = format!("{}{}", secure_base, endpoint);
|
||||
let _secure_response = reqwest::blocking::get(&secure_full).unwrap();
|
||||
|
||||
// BAD: HTTP protocol string
|
||||
let protocol = "http://"; // $ Source
|
||||
let host = "api.example.com";
|
||||
let insecure_url = format!("{}{}", protocol, host);
|
||||
let _insecure_response = reqwest::blocking::get(&insecure_url).unwrap(); // $ Alert[rust/non-https-url]
|
||||
|
||||
// GOOD: HTTPS protocol string
|
||||
let secure_protocol = "https://";
|
||||
let secure_url = format!("{}{}", secure_protocol, host);
|
||||
let _secure_response2 = reqwest::blocking::get(&secure_url).unwrap();
|
||||
}
|
||||
|
||||
fn test_localhost_exemptions() {
|
||||
// GOOD: localhost URLs should not be flagged (local development)
|
||||
let _local1 = reqwest::blocking::get("http://localhost:8080/api").unwrap();
|
||||
let _local2 = reqwest::blocking::get("HTTP://LOCALHOST:8080/api").unwrap();
|
||||
let _local3 = reqwest::blocking::get("http://127.0.0.1:3000/test").unwrap();
|
||||
let _local4 = reqwest::blocking::get("http://192.168.1.100/internal").unwrap();
|
||||
let _local5 = reqwest::blocking::get("http://10.0.0.1/admin").unwrap();
|
||||
let _local6 = reqwest::blocking::get("http://172.16.0.0/foo").unwrap();
|
||||
let _local7 = reqwest::blocking::get("http://172.31.255.255/bar").unwrap();
|
||||
|
||||
// GOOD: test IPv6 localhost variants
|
||||
let _local8 = reqwest::blocking::get("http://[::1]:8080/api").unwrap();
|
||||
let _local9 = reqwest::blocking::get("http://[0:0:0:0:0:0:0:1]/test").unwrap();
|
||||
|
||||
// BAD: non-private IP address
|
||||
let _local10 = reqwest::blocking::get("http://172.32.0.0/baz").unwrap(); // $ Alert[rust/non-https-url]
|
||||
|
||||
}
|
||||
|
||||
// Additional test cases that mirror the Bad/Good examples
|
||||
fn test_examples() {
|
||||
// From UseOfHttpBad.rs - BAD case
|
||||
{
|
||||
let url = "http://example.com/sensitive-data"; // $ Source
|
||||
|
||||
// This makes an insecure HTTP request that can be intercepted
|
||||
let response = reqwest::blocking::get(url).unwrap(); // $ Alert[rust/non-https-url]
|
||||
println!("Response: {}", response.text().unwrap());
|
||||
}
|
||||
|
||||
// From UseOfHttpGood.rs - GOOD case
|
||||
{
|
||||
let url = "https://example.com/sensitive-data";
|
||||
|
||||
// This makes a secure HTTPS request that is encrypted
|
||||
let response = reqwest::blocking::get(url).unwrap();
|
||||
println!("Response: {}", response.text().unwrap());
|
||||
}
|
||||
}
|
||||
3
rust/ql/test/query-tests/security/CWE-319/options.yml
Normal file
3
rust/ql/test/query-tests/security/CWE-319/options.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
qltest_cargo_check: true
|
||||
qltest_dependencies:
|
||||
- reqwest = { version = "0.12.9", features = ["blocking"] }
|
||||
Reference in New Issue
Block a user