Use Absolutize for files that do not exist
Canonicalize relies on the file existing to resolve the potential traversal, which won't work for file upload in case the file name has a traversal inside it.
This commit is contained in:
13
src/files.rs
13
src/files.rs
@@ -1,3 +1,4 @@
|
||||
use path_absolutize::*;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::read_dir;
|
||||
use std::io;
|
||||
@@ -47,10 +48,10 @@ fn is_valid_full_path(base: &Path, path: &str) -> Option<PathBuf> {
|
||||
let mut full_path = PathBuf::from(base);
|
||||
full_path.push(&path);
|
||||
full_path
|
||||
.canonicalize()
|
||||
.absolutize()
|
||||
.and_then(|p| {
|
||||
if p.starts_with(base) {
|
||||
Ok(p)
|
||||
Ok(p.into_owned())
|
||||
} else {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
@@ -59,9 +60,9 @@ fn is_valid_full_path(base: &Path, path: &str) -> Option<PathBuf> {
|
||||
}
|
||||
})
|
||||
.ok()
|
||||
} else if let Ok(path) = path.canonicalize().and_then(|path| {
|
||||
} else if let Ok(path) = path.absolutize().and_then(|path| {
|
||||
if path.starts_with(base) {
|
||||
Ok(path)
|
||||
Ok(path.into_owned())
|
||||
} else {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
@@ -88,9 +89,7 @@ mod tests {
|
||||
assert_eq!(None, is_valid_path("fake/../../../"));
|
||||
assert_eq!(None, is_valid_path("../../../etc/passwd"));
|
||||
assert_eq!(None, is_valid_path("..//etc/passwd"));
|
||||
assert_eq!(None, is_valid_path("..%2f..%2f/etc/passwd"));
|
||||
assert_eq!(None, is_valid_path("%2e%2e%2f%2e%2e%2f/etc/passwd"));
|
||||
assert_eq!(None, is_valid_path("\\\\attacker.com\\shared\\mal.php"));
|
||||
assert_eq!(None, is_valid_path("../../etc/passwd"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user