diff --git a/session.go b/session.go index ea44d92..916ad9a 100644 --- a/session.go +++ b/session.go @@ -199,6 +199,7 @@ type FileSystemRouter struct { // func (fs *FileSystemRouter) Router() Middleware { pathinfoRe := regexp.MustCompile(`^(.+\.php)(/?.+)$`) + docroot := filepath.Join(fs.DocRoot) // converts to absolute path return func(inner SessionHandler) SessionHandler { return func(client Client, req *Request) (*ResponsePipe, error) { @@ -213,11 +214,18 @@ func (fs *FileSystemRouter) Router() Middleware { } req.Params["PATH_INFO"] = fastcgiPathInfo - req.Params["PATH_TRANSLATED"] = filepath.Join(fs.DocRoot, fastcgiPathInfo) + req.Params["PATH_TRANSLATED"] = filepath.Join(docroot, fastcgiPathInfo) req.Params["SCRIPT_NAME"] = fastcgiScriptName - req.Params["SCRIPT_FILENAME"] = filepath.Join(fs.DocRoot, fastcgiScriptName) + req.Params["SCRIPT_FILENAME"] = filepath.Join(docroot, fastcgiScriptName) req.Params["DOCUMENT_URI"] = r.URL.Path - req.Params["DOCUMENT_ROOT"] = fs.DocRoot + req.Params["DOCUMENT_ROOT"] = docroot + + // check if the script filename is within docroot. + // triggers error if not. + if !strings.HasPrefix(req.Params["SCRIPT_FILENAME"], docroot) { + err := fmt.Errorf("error: access path outside of filesystem docroot") + return nil, err + } // handle directory index urlPath := r.URL.Path diff --git a/session_test.go b/session_test.go index 057f90f..2f1ec99 100644 --- a/session_test.go +++ b/session_test.go @@ -179,3 +179,35 @@ func TestMapFilterRequest(t *testing.T) { return } } + +func TestFileSystemRouter(t *testing.T) { + fs := &gofast.FileSystemRouter{ + DocRoot: "/non-exists/folder/structure", + Exts: []string{"php"}, + DirIndex: []string{"index.php"}, + } + + h := gofast.Chain( + gofast.BasicParamsMap, + fs.Router(), + )(func(client gofast.Client, req *gofast.Request) (resp *gofast.ResponsePipe, err error) { + t.Logf("SCRIPT_FILENAME: %s", req.Params["SCRIPT_FILENAME"]) + return + }) + + r, err := http.NewRequest("GET", "http://foobar.com/", nil) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + r.URL.Path = "/../../hello-escape" + + _, err = h(nil, gofast.NewRequest(r)) + if err == nil { + t.Errorf("expected error, got nil") + return + } + + if want, have := "error: access path outside of filesystem docroot", err.Error(); want != have { + t.Errorf("expected \"%s\", got \"%s\"", want, have) + } +}