How to check if a file is inside a directory (or a subdirectory) ?

2,478 views
Skip to first unread message

Pierre Durand

unread,
Jun 7, 2016, 11:19:14 AM6/7/16
to golang-nuts
Hi!

I want to check if a file is inside a directory (or a subdirectory).
Can I just check if the file's path begins with the directory's path?
Shoud I use filepath.Abs() or filepath.Clean()?

My use case is:
I have a variable named "root" which is a directory path.
I also have a file path, relative to "root".
I generate the "real" file path with filepath.Join(root, myfile).
The file path is given by the user, and I want to prevent the user to go "outside the root".

As far as I tested, using filepath.Join() and checking that the "real" file path begins with my "root" variable is OK.
Is there a security issue? (symlink...)

Thanks!

Shawn Milochik

unread,
Jun 7, 2016, 11:28:32 AM6/7/16
to golang-nuts
According to the docs here: https://golang.org/pkg/path/filepath/#Abs
"Abs returns an absolute representation of path. If the path is not absolute it will be joined with the current working directory to turn it into an absolute path. The absolute path name for a given file is not guaranteed to be unique."

Since that mentions using the current working directory, note this in the os.Getwd() docs here: https://golang.org/pkg/os/#Getwd
"If the current directory can be reached via multiple paths (due to symbolic links), Getwd may return any one of them."

So, technically you can't rely on the absolute path matching your root, as provided, because it could be a different path pointing to the same place.

Even if that were true, you could never rely on the path starting with your root, or the user could provide ../../../../../filename.txt and back out of your root folder.

You could use filepath.Walk (https://golang.org/pkg/path/filepath/#Walk) and take inventory of all the files within your root path, and compare user input to that list. Then use only your cached path from the Walk to perform actions on the file.


as....@gmail.com

unread,
Jun 7, 2016, 12:10:33 PM6/7/16
to golang-nuts
Look at how net/http does it: https://golang.org/src/net/http/fs.go#L26

For something more abstract, see https://godoc.org/golang.org/x/tools/godoc/vfs 

Michael Jones

unread,
Jun 7, 2016, 2:36:08 PM6/7/16
to as....@gmail.com, golang-nuts
In a UNIX/Linux/MACOS/… world you could get the inode number of the directory, form an absolute path from the user’s filename, and the traverse the abs path looking for a directory matching the inode number. May not be the fastest possible way but certainly a way that will work. (Slight reservation about mounted file systems…hmm…)

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Pierre Durand

unread,
Jun 7, 2016, 3:14:14 PM6/7/16
to golang-nuts, as....@gmail.com
Thank you as...@gmail.com

> filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
is what I need
Reply all
Reply to author
Forward
0 new messages