66 lines
2.1 KiB
Markdown
66 lines
2.1 KiB
Markdown
## `filepath-securejoin` ##
|
|
|
|
[![Build Status](https://travis-ci.org/cyphar/filepath-securejoin.svg?branch=master)](https://travis-ci.org/cyphar/filepath-securejoin)
|
|
|
|
An implementation of `SecureJoin`, a [candidate for inclusion in the Go
|
|
standard library][go#20126]. The purpose of this function is to be a "secure"
|
|
alternative to `filepath.Join`, and in particular it provides certain
|
|
guarantees that are not provided by `filepath.Join`.
|
|
|
|
This is the function prototype:
|
|
|
|
```go
|
|
func SecureJoin(root, unsafePath string) (string, error)
|
|
```
|
|
|
|
This library **guarantees** the following:
|
|
|
|
* If no error is set, the resulting string **must** be a child path of
|
|
`SecureJoin` and will not contain any symlink path components (they will all
|
|
be expanded).
|
|
|
|
* When expanding symlinks, all symlink path components **must** be resolved
|
|
relative to the provided root. In particular, this can be considered a
|
|
userspace implementation of how `chroot(2)` operates on file paths. Note that
|
|
these symlinks will **not** be expanded lexically (`filepath.Clean` is not
|
|
called on the input before processing).
|
|
|
|
* Non-existant path components are unaffected by `SecureJoin` (similar to
|
|
`filepath.EvalSymlinks`'s semantics).
|
|
|
|
* The returned path will always be `filepath.Clean`ed and thus not contain any
|
|
`..` components.
|
|
|
|
A (trivial) implementation of this function on GNU/Linux systems could be done
|
|
with the following (note that this requires root privileges and is far more
|
|
opaque than the implementation in this library, and also requires that
|
|
`readlink` is inside the `root` path):
|
|
|
|
```go
|
|
package securejoin
|
|
|
|
import (
|
|
"os/exec"
|
|
"path/filepath"
|
|
)
|
|
|
|
func SecureJoin(root, unsafePath string) (string, error) {
|
|
unsafePath = string(filepath.Separator) + unsafePath
|
|
cmd := exec.Command("chroot", root,
|
|
"readlink", "--canonicalize-missing", "--no-newline", unsafePath)
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
expanded := string(output)
|
|
return filepath.Join(root, expanded), nil
|
|
}
|
|
```
|
|
|
|
[go#20126]: https://github.com/golang/go/issues/20126
|
|
|
|
### License ###
|
|
|
|
The license of this project is the same as Go, which is a BSD 3-clause license
|
|
available in the `LICENSE` file.
|