Из «Случай окисления: язык программирования Rust» Серхио Бенитес говорит:
Here is a static file server written in Rocket. It is exactly four lines and it guaranteed to not be vulnerable to directory traversal attacks.
Вот эти четыре строки:
#[get("/<path..>")]
fn files(path: PathBuf) -> Option<NamedFile> {
NamedFile::open(Path::new("static/").join(path)).ok()
}
В нижней части этого слайда говорится:
FromParam*
реализация для PathBuf
проверяет безопасность путиЯ понимаю, как тип может гарантировать безопасность, проверяя ввод (в том же смысле, что любой объект может в конструкторе, или как ввод в функцию может быть обернут проверяющей функцией.
dangerousThing(validateSafety(input))
Многие языки обеспечивают это. Я также понимаю, как это можно упростить, поместив его в конструктор для типа или класса,
class Path {
constructor(path) { this._path = validateSafety(path) }
}
Но меня смущает то, что (если что-то) Rust здесь делает по-другому. Есть ли что-то еще?
PathBuf
не дает таких гарантий. Это не можем, потому что во всех доменах, где используется PathBuf
, нет концепции «атак с обходом каталога».
Автор имеет в виду, что реализация FromSegments
для PathBuf
выполняет проверку обходной атаки и никогда не вызывает обработчик в случае сбоя.
FromSegments
допускает случаи сбоя, возвращая Result
:
pub trait FromSegments<'a>: Sized {
type Error: Debug;
fn from_segments(segments: Segments<'a>) -> Result<Self, Self::Error>;
}
Мы можем перебирать части пути с помощью components()
, поэтому мы можем проверить использование ..
, как показано ниже:
let p = PathBuf::from_str("/tmp/../etc/password").unwrap();
if p.components().into_iter().any(|x| x == Component::ParentDir) {
return Err("directory traversal");
}
Значит, это просто конструктор для типа, который принимает ввод, проверяет
../
(или родительскую нотацию) и не может создать тип во время выполнения, если он обнаружен?