Skip to content

Commit

Permalink
Add allow-lists for HTTP requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
brendandburns committed Jun 2, 2023
1 parent c557e81 commit d3be496
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 30 deletions.
5 changes: 4 additions & 1 deletion crates/test-programs/tests/wasi-http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,15 @@ pub fn run(name: &str) -> anyhow::Result<()> {

// Create our wasi context.
let builder = WasiCtxBuilder::new().inherit_stdio().arg(name)?;
let mut wasi_http = WasiHttp::new();
wasi_http.allowed_methods = vec!["GET".to_string(), "POST".to_string(), "PUT".to_string()];
wasi_http.allowed_authorities = vec!["localhost:3000".to_string()];

let mut store = Store::new(
&ENGINE,
Ctx {
wasi: builder.build(),
http: WasiHttp::new(),
http: wasi_http,
},
);

Expand Down
32 changes: 32 additions & 0 deletions crates/test-programs/wasi-http-tests/src/bin/outbound_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,5 +184,37 @@ fn main() -> Result<()> {
"Error::UnexpectedError(\"unsupported scheme WS\")"
);

// Delete is not an allowed method in this test.
let r6 = request(
types::MethodParam::Delete,
types::SchemeParam::Http,
"localhost:3000",
"/",
"",
&[],
);

let error = r6.unwrap_err();
assert_eq!(
error.to_string(),
"ErrorResult::UnexpectedError(\"Method DELETE is not allowed.\")"
);

// localhost:8080 is not an allowed authority in this test.
let r7 = request(
types::MethodParam::Get,
types::SchemeParam::Http,
"localhost:8080",
"/",
"",
&[],
);

let error = r7.unwrap_err();
assert_eq!(
error.to_string(),
"ErrorResult::UnexpectedError(\"Authority localhost:8080 is not allowed.\")"
);

Ok(())
}
59 changes: 32 additions & 27 deletions crates/wasi-http/src/http_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ fn port_for_scheme(scheme: &Option<Scheme>) -> &str {
}
}

fn is_allowed(allow_list: &Vec<String>, value: String) -> bool {
for allowed in allow_list.iter() {
if allowed == "*" {
return true;
}
if value == *allowed {
return true;
}
}
false
}

impl WasiHttp {
pub(crate) async fn handle_async(
&mut self,
Expand Down Expand Up @@ -82,19 +94,7 @@ impl WasiHttp {
crate::wasi::http::types::Method::Other(s) => bail!("unknown method {}", s),
};

let mut allowed = false;
let method_str = request.method.to_string();
for allowed_method in self.allowed_methods.iter() {
if allowed_method == "*" {
allowed = true;
break;
}
if method_str == *allowed_method {
allowed = true;
break;
}
}
if !allowed {
if !is_allowed(&self.allowed_methods, method.to_string()) {
bail!("Method {} is not allowed.", method.to_string());
}

Expand All @@ -104,27 +104,32 @@ impl WasiHttp {
Scheme::Other(s) => bail!("unsupported scheme {}", s),
};

let mut allowed = false;
let scheme_str = request.scheme.to_string();
for allowed_scheme in self.allowed_schemes.iter() {
if allowed_scheme == "*" {
allowed = true;
break;
}
if scheme_str == *allowed_scheme {
allowed = true;
break;
}
}
if !allowed {
bail!("Scheme {} is not allowed.", scheme_str);
if !is_allowed(
&self.allowed_schemes,
request
.scheme
.as_ref()
.unwrap_or(&Scheme::Https)
.to_string(),
) {
bail!(
"Scheme {} is not allowed.",
request
.scheme
.as_ref()
.unwrap_or(&Scheme::Https)
.to_string()
);
}

// Largely adapted from https://hyper.rs/guides/1/client/basic/
let authority = match request.authority.find(":") {
Some(_) => request.authority.clone(),
None => request.authority.clone() + port_for_scheme(&request.scheme),
};
if !is_allowed(&self.allowed_authorities, authority.clone()) {
bail!("Authority {} is not allowed.", authority);
}
let mut sender = if scheme == "https://" {
#[cfg(not(any(target_arch = "riscv64", target_arch = "s390x")))]
{
Expand Down
6 changes: 4 additions & 2 deletions crates/wasi-http/src/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub struct WasiHttp {

pub allowed_methods: Vec<String>,
pub allowed_schemes: Vec<String>,
pub allowed_authorities: Vec<String>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -152,8 +153,9 @@ impl WasiHttp {
fields: HashMap::new(),
streams: HashMap::new(),
futures: HashMap::new(),
allowed_methods: vec!("*".to_string()),
allowed_schemes: vec!("*".to_string()),
allowed_methods: vec!["*".to_string()],
allowed_schemes: vec!["*".to_string()],
allowed_authorities: vec!["*".to_string()],
}
}
}

0 comments on commit d3be496

Please sign in to comment.