mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Rust: Address PR feedback
This commit is contained in:
@@ -54,7 +54,7 @@ module Xss {
|
||||
private class HeuristicHtmlEncodingBarrier extends Barrier {
|
||||
HeuristicHtmlEncodingBarrier() {
|
||||
exists(Call fc |
|
||||
fc.getStaticTarget().(Function).getName().getText().regexpMatch(".*(escape|encode).*") and
|
||||
fc.getStaticTarget().getName().getText().regexpMatch(".*(escape|encode).*") and
|
||||
fc.getArgument(_) = this.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query `rust/xss`, to detect XSS security vulnerabilities.
|
||||
* Added a new a query `rust/xss`, to detect cross-site scripting security vulnerabilities.
|
||||
|
||||
@@ -10,20 +10,22 @@ scripting vulnerability.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>To guard against cross-site scripting, consider encoding/escaping the unstrusted
|
||||
<p>To guard against cross-site scripting, consider encoding/escaping the untrusted
|
||||
input before including it in the HTML.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
<p>The following example shows a simple web handler that writes a path of the
|
||||
URL parameter directly to an HTML response, leaving the website vulnerable to
|
||||
cross-site scripting:</p>
|
||||
<p>The following example shows a simple web handler that writes a URL path parameter
|
||||
directly to an HTML response, leaving the website vulnerable to cross-site
|
||||
scripting:</p>
|
||||
|
||||
<sample src="XSSBad.rs" />
|
||||
|
||||
<p>To fix this vulnerability, the user input should be HTML-encoded before being
|
||||
included in the response:</p>
|
||||
included in the response. In the following example <code>encode_text</code> from
|
||||
the <a href="https://docs.rs/html-escape/latest/html_escape/index.html">html_escape</a>
|
||||
crate is used:</p>
|
||||
|
||||
<sample src="XSSGood.rs" />
|
||||
|
||||
@@ -36,7 +38,7 @@ included in the response:</p>
|
||||
(Cross Site Scripting) Prevention Cheat Sheet</a>.
|
||||
</li>
|
||||
<li>
|
||||
Wikipedia: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>.
|
||||
Wikipedia: <a href="https://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP:
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use actix_web::{web, HttpResponse, Result};
|
||||
use askama::Template;
|
||||
|
||||
// GOOD: Manual HTML encoding using an `html_escape` function
|
||||
// GOOD: Manual HTML encoding using an `html_escape::encode_text` function
|
||||
async fn safe_handler_with_encoding(path: web::Path<String>) -> impl Responder {
|
||||
let user_input = path.into_inner();
|
||||
let escaped_input = html_escape(&user_input);
|
||||
|
||||
let escaped_input = html_escape::encode_text(&user_input);
|
||||
let html = format!(
|
||||
r#"
|
||||
<!DOCTYPE html>
|
||||
|
||||
@@ -31,6 +31,7 @@ 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.XssExtensions
|
||||
|
||||
/**
|
||||
* Gets a count of the total number of lines of code in the database.
|
||||
|
||||
@@ -509,6 +509,15 @@ version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
|
||||
[[package]]
|
||||
name = "html-escape"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476"
|
||||
dependencies = [
|
||||
"utf8-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
@@ -1094,6 +1103,7 @@ name = "test"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"html-escape",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1228,6 +1238,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
|
||||
@@ -5,7 +5,7 @@ use actix_web::{
|
||||
};
|
||||
|
||||
// The "bad" example from the qldoc
|
||||
#[get("/bad/{a}")] // $ Source
|
||||
#[get("/bad/{a}")] // $ Source=a
|
||||
async fn vulnerable_handler(path: web::Path<String>) -> impl Responder {
|
||||
let user_input = path.into_inner();
|
||||
|
||||
@@ -22,7 +22,7 @@ async fn vulnerable_handler(path: web::Path<String>) -> impl Responder {
|
||||
user_input
|
||||
);
|
||||
|
||||
Html::new(html) // $ Alert[rust/xss]
|
||||
Html::new(html) // $ Alert[rust/xss]=a
|
||||
}
|
||||
|
||||
fn html_escape(s: &str) -> String {
|
||||
@@ -42,7 +42,7 @@ fn html_escape(s: &str) -> String {
|
||||
// The "good" example from the qldoc
|
||||
async fn safe_handler_with_encoding(path: web::Path<String>) -> impl Responder {
|
||||
let user_input = path.into_inner();
|
||||
let escaped_input = html_escape(&user_input);
|
||||
let escaped_input = html_escape::encode_text(&user_input);
|
||||
|
||||
let html = format!(
|
||||
r#"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
qltest_use_nightly: true
|
||||
qltest_dependencies:
|
||||
- actix-web = { version = "4.12.0" }
|
||||
- actix-web = { version = "4.12.0" }
|
||||
- html-escape = { version = "0.2.13" }
|
||||
@@ -1,27 +1,27 @@
|
||||
#select
|
||||
| main.rs:12:13:12:29 | ...::html | main.rs:9:10:9:12 | map | main.rs:12:13:12:29 | ...::html | Cross-site scripting vulnerability due to a $@. | main.rs:9:10:9:12 | map | user-provided value |
|
||||
| main.rs:10:13:10:29 | ...::html | main.rs:7:10:7:12 | map | main.rs:10:13:10:29 | ...::html | Cross-site scripting vulnerability due to a $@. | main.rs:7:10:7:12 | map | user-provided value |
|
||||
edges
|
||||
| main.rs:9:10:9:12 | map | main.rs:9:15:9:26 | ...: String | provenance | Src:MaD:2 |
|
||||
| main.rs:9:15:9:26 | ...: String | main.rs:11:32:11:56 | MacroExpr | provenance | |
|
||||
| main.rs:11:17:11:20 | body | main.rs:12:31:12:34 | body | provenance | |
|
||||
| main.rs:11:32:11:56 | ...::format(...) | main.rs:11:32:11:56 | { ... } | provenance | |
|
||||
| main.rs:11:32:11:56 | ...::must_use(...) | main.rs:11:17:11:20 | body | provenance | |
|
||||
| main.rs:11:32:11:56 | MacroExpr | main.rs:11:32:11:56 | ...::format(...) | provenance | MaD:3 |
|
||||
| main.rs:11:32:11:56 | { ... } | main.rs:11:32:11:56 | ...::must_use(...) | provenance | MaD:4 |
|
||||
| main.rs:12:31:12:34 | body | main.rs:12:13:12:29 | ...::html | provenance | MaD:1 Sink:MaD:1 |
|
||||
| main.rs:7:10:7:12 | map | main.rs:7:15:7:26 | ...: String | provenance | Src:MaD:2 |
|
||||
| main.rs:7:15:7:26 | ...: String | main.rs:9:32:9:56 | MacroExpr | provenance | |
|
||||
| main.rs:9:17:9:20 | body | main.rs:10:31:10:34 | body | provenance | |
|
||||
| main.rs:9:32:9:56 | ...::format(...) | main.rs:9:32:9:56 | { ... } | provenance | |
|
||||
| main.rs:9:32:9:56 | ...::must_use(...) | main.rs:9:17:9:20 | body | provenance | |
|
||||
| main.rs:9:32:9:56 | MacroExpr | main.rs:9:32:9:56 | ...::format(...) | provenance | MaD:3 |
|
||||
| main.rs:9:32:9:56 | { ... } | main.rs:9:32:9:56 | ...::must_use(...) | provenance | MaD:4 |
|
||||
| main.rs:10:31:10:34 | body | main.rs:10:13:10:29 | ...::html | provenance | MaD:1 Sink:MaD:1 |
|
||||
models
|
||||
| 1 | Sink: warp::reply::html; Argument[0]; html-injection |
|
||||
| 2 | Source: <_ as warp::filter::Filter>::map; Argument[0].Parameter[0..7]; remote |
|
||||
| 3 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
|
||||
| 4 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
|
||||
nodes
|
||||
| main.rs:9:10:9:12 | map | semmle.label | map |
|
||||
| main.rs:9:15:9:26 | ...: String | semmle.label | ...: String |
|
||||
| main.rs:11:17:11:20 | body | semmle.label | body |
|
||||
| main.rs:11:32:11:56 | ...::format(...) | semmle.label | ...::format(...) |
|
||||
| main.rs:11:32:11:56 | ...::must_use(...) | semmle.label | ...::must_use(...) |
|
||||
| main.rs:11:32:11:56 | MacroExpr | semmle.label | MacroExpr |
|
||||
| main.rs:11:32:11:56 | { ... } | semmle.label | { ... } |
|
||||
| main.rs:12:13:12:29 | ...::html | semmle.label | ...::html |
|
||||
| main.rs:12:31:12:34 | body | semmle.label | body |
|
||||
| main.rs:7:10:7:12 | map | semmle.label | map |
|
||||
| main.rs:7:15:7:26 | ...: String | semmle.label | ...: String |
|
||||
| main.rs:9:17:9:20 | body | semmle.label | body |
|
||||
| main.rs:9:32:9:56 | ...::format(...) | semmle.label | ...::format(...) |
|
||||
| main.rs:9:32:9:56 | ...::must_use(...) | semmle.label | ...::must_use(...) |
|
||||
| main.rs:9:32:9:56 | MacroExpr | semmle.label | MacroExpr |
|
||||
| main.rs:9:32:9:56 | { ... } | semmle.label | { ... } |
|
||||
| main.rs:10:13:10:29 | ...::html | semmle.label | ...::html |
|
||||
| main.rs:10:31:10:34 | body | semmle.label | body |
|
||||
subpaths
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
//! Tests for XSS
|
||||
//!
|
||||
use warp::Filter;
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
let hello = warp::path("greet")
|
||||
.and(warp::path::param())
|
||||
.map(|name: String| { // $ Source
|
||||
.map(|name: String| { // $ Source=name
|
||||
// Vulnerable to XSS because it directly includes user input in the response
|
||||
let body = format!("<h1>Hello, {name}!</h1>");
|
||||
warp::reply::html(body) // $ Alert[rust/xss]
|
||||
warp::reply::html(body) // $ Alert[rust/xss]=name
|
||||
});
|
||||
|
||||
// Start the web server on port 3000
|
||||
|
||||
Reference in New Issue
Block a user