Prevent directory traversal attack

This commit is contained in:
Thomas Harmon 2021-03-09 14:33:22 -05:00
parent e29f0c5468
commit fb278de4b4
4 changed files with 26 additions and 1 deletions

View File

@ -1,6 +1,10 @@
# Changes
## Unreleased - 2021-xx-xx
* Prevent directory traversal attack by checking if the request path is a
descendant of the `serve_from` directory. E.g., if the files are served from
`./test/`, and someone requests `..%5c/some-secret-file`, they will get a
Forbidden response.
## 0.6.0-beta.2 - 2021-02-10

View File

@ -73,7 +73,8 @@ impl Files {
///
/// The second argument (`serve_from`) is the location on disk at which files are loaded.
/// This can be a relative path. For example, `./` would serve files from the current
/// working directory.
/// working directory. Requests for files outside of the `serve_from` directory
/// will receive a Forbidden Response.
///
/// # Implementation Notes
/// If the mount path is set as the root path `/`, services registered after this one will

View File

@ -88,6 +88,18 @@ impl Service<ServiceRequest> for FilesService {
Err(e) => return self.handle_err(e, req),
};
let is_path_descendant = path
.as_path()
.ancestors()
.any(|ancestor| ancestor == self.directory.as_path());
if !is_path_descendant {
return Either::Left(ok(req.into_response(
actix_web::HttpResponse::Forbidden()
.insert_header(header::ContentType(mime::TEXT_PLAIN_UTF_8))
.body("Requested files outside the server."),
)));
}
if path.is_dir() {
if let Some(ref redir_index) = self.index {
if self.redirect_to_slash && !req.path().ends_with('/') {

View File

@ -35,4 +35,12 @@ async fn test_utf8_file_contents() {
res.headers().get(header::CONTENT_TYPE),
Some(&HeaderValue::from_static("text/plain; charset=utf-8")),
);
// prevent directory traversal attack
let srv = test::init_service(App::new().service(Files::new("/", "./tests"))).await;
let req = TestRequest::with_uri("..%5c/README.md").to_request();
let res = test::call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::FORBIDDEN);
}