Skip to content

Commit

Permalink
prevent path traversal outside content directory
Browse files Browse the repository at this point in the history
  • Loading branch information
MultiFox200 committed Jun 24, 2024
1 parent 271a70e commit bbf1f7d
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 6 deletions.
23 changes: 22 additions & 1 deletion src/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,29 @@ func (app *App) GetOrCreateResponseItem(requestedPath string, compression Compre
return &responseItem, 0
}

func (app *App) GetFilePath(urlPath string) (string, bool) {
requestedPath := path.Join(app.params.Directory, urlPath)

requestedPath, err := filepath.EvalSymlinks(requestedPath)
if err != nil {
return "", false
}

if !strings.HasPrefix(requestedPath, app.params.Directory) {
return "", false
}

return requestedPath, true
}

func (app *App) HandlerFuncNew(w http.ResponseWriter, r *http.Request) {
requestedPath := path.Join(app.params.Directory, r.URL.Path)
requestedPath, valid := app.GetFilePath(r.URL.Path)

if !valid {
w.WriteHeader(http.StatusNotFound)
return
}

responseItem, errorCode := app.GetOrCreateResponseItem(requestedPath, None, nil)
if errorCode != 0 {
w.WriteHeader(errorCode)
Expand Down
37 changes: 37 additions & 0 deletions src/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,40 @@ func TestListen(t *testing.T) {

a.Listen()
}

func TestGetFilePath(t *testing.T) {
params := param.Params{
Address: "0.0.0.0",
Port: 8080,
Gzip: false,
Brotli: true,
Threshold: 1024,
Directory: "../../test/frontend/dist",
CacheControlMaxAge: 99999999999,
SpaMode: true,
IgnoreCacheControlPaths: []string{"../../test/frontend/dist/example.html"},
CacheEnabled: true,
CacheBuffer: 50 * 1024,
}
app := app.NewApp(&params)

_, valid := app.GetFilePath("../test/index.html")
if valid {
t.Errorf("Expected false, got %t", valid)
}

_, valid = app.GetFilePath("../../test/index.html")
if valid {
t.Errorf("Expected false, got %t", valid)
}

_, valid = app.GetFilePath("test/../index.html")
if !valid {
t.Errorf("Expected false, got %t", valid)
}

_, valid = app.GetFilePath("test/../test/../index.html")
if !valid {
t.Errorf("Expected false, got %t", valid)
}
}
5 changes: 4 additions & 1 deletion src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ func main() {
Name: "spa-to-http",
Flags: param.Flags,
Action: func(c *cli.Context) error {
params := param.ContextToParams(c)
params, err := param.ContextToParams(c)
if err != nil {
return err
}

newApp := app.NewApp(params)
go newApp.CompressFiles()
Expand Down
12 changes: 9 additions & 3 deletions src/param/param.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package param

import (
"github.com/urfave/cli/v2"
"path/filepath"
)

var Flags = []cli.Flag{
Expand Down Expand Up @@ -98,14 +99,19 @@ type Params struct {
//DirectoryListing bool
}

func ContextToParams(c *cli.Context) *Params {
func ContextToParams(c *cli.Context) (*Params, error) {
directory, err := filepath.Abs(c.String("directory"))
if err != nil {
return nil, err
}

return &Params{
Address: c.String("address"),
Port: c.Int("port"),
Gzip: c.Bool("gzip"),
Brotli: c.Bool("brotli"),
Threshold: c.Int64("threshold"),
Directory: c.String("directory"),
Directory: directory,
CacheControlMaxAge: c.Int64("cache-max-age"),
SpaMode: c.Bool("spa"),
IgnoreCacheControlPaths: c.StringSlice("ignore-cache-control-paths"),
Expand All @@ -114,5 +120,5 @@ func ContextToParams(c *cli.Context) *Params {
Logger: c.Bool("logger"),
LogPretty: c.Bool("log-pretty"),
//DirectoryListing: c.Bool("directory-listing"),
}
}, nil
}
6 changes: 5 additions & 1 deletion src/param/param_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ func TestContextToParams(t *testing.T) {

ctx := cli.NewContext(nil, f, nil)
ctx.Context = context.WithValue(context.Background(), "key", "val")
params := param.ContextToParams(ctx)
params, err := param.ContextToParams(ctx)
if err != nil {
t.Errorf("Error: %s", err)
return
}

if params.Address != e_adress {
t.Errorf("Got %s, expected %s", params.Address, e_adress)
Expand Down

0 comments on commit bbf1f7d

Please sign in to comment.