diff options
author | Jikstra <34889164+Jikstra@users.noreply.github.com> | 2021-09-10 13:56:31 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-10 13:56:31 +0000 |
commit | d0cd4f0f21210cae8677941f6ca4059365767879 (patch) | |
tree | 623b58e978ef1c31c11553a5b077f51432a34f84 /tests | |
parent | Apply requested changes (diff) | |
parent | Merge pull request #598 from svenstaro/dependabot/cargo/sha2-0.9.8 (diff) | |
download | miniserve-d0cd4f0f21210cae8677941f6ca4059365767879.tar.gz miniserve-d0cd4f0f21210cae8677941f6ca4059365767879.zip |
Merge branch 'master' into feat_raw_mode
Diffstat (limited to 'tests')
-rw-r--r-- | tests/upload_files.rs | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/tests/upload_files.rs b/tests/upload_files.rs index 698eb46..5e764ba 100644 --- a/tests/upload_files.rs +++ b/tests/upload_files.rs @@ -1,6 +1,7 @@ mod fixtures; -use fixtures::{server, Error, TestServer}; +use assert_fs::fixture::TempDir; +use fixtures::{server, server_no_stderr, tmpdir, Error, TestServer}; use reqwest::blocking::{multipart, Client}; use rstest::rstest; use select::document::Document; @@ -78,3 +79,91 @@ fn uploading_files_is_prevented(server: TestServer) -> Result<(), Error> { Ok(()) } + +/// Test for path traversal vulnerability (CWE-22) in both path parameter of query string and in +/// file name (Content-Disposition) +/// +/// see: https://github.com/svenstaro/miniserve/issues/518 +#[rstest] +#[case("foo", "bar", "foo/bar")] +#[case("/../foo", "bar", "foo/bar")] +#[case("/foo", "/../bar", "foo/bar")] +#[case("C:/foo", "C:/bar", if cfg!(windows) { "foo/bar" } else { "C:/foo/C:/bar" })] +#[case(r"C:\foo", r"C:\bar", if cfg!(windows) { "foo/bar" } else { r"C:\foo/C:\bar" })] +#[case(r"\foo", r"\..\bar", if cfg!(windows) { "foo/bar" } else { r"\foo/\..\bar" })] +fn prevent_path_traversal_attacks( + #[with(&["-u"])] server: TestServer, + #[case] path: &str, + #[case] filename: &'static str, + #[case] expected: &str, +) -> Result<(), Error> { + // Create test directories + use std::fs::create_dir_all; + create_dir_all(server.path().join("foo")).unwrap(); + if !cfg!(windows) { + for dir in &["C:/foo/C:", r"C:\foo", r"\foo"] { + create_dir_all(server.path().join(dir)).expect(&format!("failed to create: {:?}", dir)); + } + } + + let expected_path = server.path().join(expected); + assert!(!expected_path.exists()); + + // Perform the actual upload. + let part = multipart::Part::text("this should be uploaded") + .file_name(filename) + .mime_str("text/plain")?; + let form = multipart::Form::new().part("file_to_upload", part); + + Client::new() + .post(server.url().join(&format!("/upload?path={}", path))?) + .multipart(form) + .send()? + .error_for_status()?; + + // Make sure that the file was uploaded to the expected path + assert!(expected_path.exists()); + + Ok(()) +} + +/// Test uploading to symlink directories that point outside the server root. +/// See https://github.com/svenstaro/miniserve/issues/466 +#[rstest] +#[case(server(&["-u"]), true)] +#[case(server_no_stderr(&["-u", "--no-symlinks"]), false)] +fn upload_to_symlink_directory( + #[case] server: TestServer, + #[case] ok: bool, + tmpdir: TempDir, +) -> Result<(), Error> { + #[cfg(unix)] + use std::os::unix::fs::symlink as symlink_dir; + #[cfg(windows)] + use std::os::windows::fs::symlink_dir; + + // Create symlink directory "foo" to point outside the root + let (dir, filename) = ("foo", "bar"); + symlink_dir(tmpdir.path(), server.path().join(dir)).unwrap(); + + let full_path = server.path().join(dir).join(filename); + assert!(!full_path.exists()); + + // Try to upload + let part = multipart::Part::text("this should be uploaded") + .file_name(filename) + .mime_str("text/plain")?; + let form = multipart::Form::new().part("file_to_upload", part); + + let status = Client::new() + .post(server.url().join(&format!("/upload?path={}", dir))?) + .multipart(form) + .send()? + .error_for_status(); + + // Make sure upload behave as expected + assert_eq!(status.is_ok(), ok); + assert_eq!(full_path.exists(), ok); + + Ok(()) +} |