mirror of
https://github.com/labstack/echo.git
synced 2025-01-26 03:20:08 +02:00
Bug Fix: Directory Traversal
This commit is contained in:
parent
2b36b3d1d7
commit
1beaf09740
3
echo.go
3
echo.go
@ -49,7 +49,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -486,7 +485,7 @@ func (common) static(prefix, root string, get func(string, HandlerFunc, ...Middl
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
|
name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security
|
||||||
fi, err := os.Stat(name)
|
fi, err := os.Stat(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// The access path does not exist
|
// The access path does not exist
|
||||||
|
134
echo_test.go
134
echo_test.go
@ -60,45 +60,105 @@ func TestEcho(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEchoStatic(t *testing.T) {
|
func TestEchoStatic(t *testing.T) {
|
||||||
e := New()
|
var testCases = []struct {
|
||||||
|
name string
|
||||||
|
givenPrefix string
|
||||||
|
givenRoot string
|
||||||
|
whenURL string
|
||||||
|
expectStatus int
|
||||||
|
expectHeaderLocation string
|
||||||
|
expectBodyStartsWith string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ok",
|
||||||
|
givenPrefix: "/images",
|
||||||
|
givenRoot: "_fixture/images",
|
||||||
|
whenURL: "/images/walle.png",
|
||||||
|
expectStatus: http.StatusOK,
|
||||||
|
expectBodyStartsWith: string([]byte{0x89, 0x50, 0x4e, 0x47}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "No file",
|
||||||
|
givenPrefix: "/images",
|
||||||
|
givenRoot: "_fixture/scripts",
|
||||||
|
whenURL: "/images/bolt.png",
|
||||||
|
expectStatus: http.StatusNotFound,
|
||||||
|
expectBodyStartsWith: "{\"message\":\"Not Found\"}\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Directory",
|
||||||
|
givenPrefix: "/images",
|
||||||
|
givenRoot: "_fixture/images",
|
||||||
|
whenURL: "/images/",
|
||||||
|
expectStatus: http.StatusNotFound,
|
||||||
|
expectBodyStartsWith: "{\"message\":\"Not Found\"}\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Directory Redirect",
|
||||||
|
givenPrefix: "/",
|
||||||
|
givenRoot: "_fixture",
|
||||||
|
whenURL: "/folder",
|
||||||
|
expectStatus: http.StatusMovedPermanently,
|
||||||
|
expectHeaderLocation: "/folder/",
|
||||||
|
expectBodyStartsWith: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Directory with index.html",
|
||||||
|
givenPrefix: "/",
|
||||||
|
givenRoot: "_fixture",
|
||||||
|
whenURL: "/",
|
||||||
|
expectStatus: http.StatusOK,
|
||||||
|
expectBodyStartsWith: "<!doctype html>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sub-directory with index.html",
|
||||||
|
givenPrefix: "/",
|
||||||
|
givenRoot: "_fixture",
|
||||||
|
whenURL: "/folder/",
|
||||||
|
expectStatus: http.StatusOK,
|
||||||
|
expectBodyStartsWith: "<!doctype html>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "do not allow directory traversal (backslash - windows separator)",
|
||||||
|
givenPrefix: "/",
|
||||||
|
givenRoot: "_fixture/",
|
||||||
|
whenURL: `/..\\middleware/basic_auth.go`,
|
||||||
|
expectStatus: http.StatusNotFound,
|
||||||
|
expectBodyStartsWith: "{\"message\":\"Not Found\"}\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "do not allow directory traversal (slash - unix separator)",
|
||||||
|
givenPrefix: "/",
|
||||||
|
givenRoot: "_fixture/",
|
||||||
|
whenURL: `/../middleware/basic_auth.go`,
|
||||||
|
expectStatus: http.StatusNotFound,
|
||||||
|
expectBodyStartsWith: "{\"message\":\"Not Found\"}\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
assert := assert.New(t)
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
// OK
|
e := New()
|
||||||
e.Static("/images", "_fixture/images")
|
e.Static(tc.givenPrefix, tc.givenRoot)
|
||||||
c, b := request(http.MethodGet, "/images/walle.png", e)
|
req := httptest.NewRequest(http.MethodGet, tc.whenURL, nil)
|
||||||
assert.Equal(http.StatusOK, c)
|
rec := httptest.NewRecorder()
|
||||||
assert.NotEmpty(b)
|
e.ServeHTTP(rec, req)
|
||||||
|
assert.Equal(t, tc.expectStatus, rec.Code)
|
||||||
// No file
|
body := rec.Body.String()
|
||||||
e.Static("/images", "_fixture/scripts")
|
if tc.expectBodyStartsWith != "" {
|
||||||
c, _ = request(http.MethodGet, "/images/bolt.png", e)
|
assert.True(t, strings.HasPrefix(body, tc.expectBodyStartsWith))
|
||||||
assert.Equal(http.StatusNotFound, c)
|
} else {
|
||||||
|
assert.Equal(t, "", body)
|
||||||
// Directory
|
}
|
||||||
e.Static("/images", "_fixture/images")
|
|
||||||
c, _ = request(http.MethodGet, "/images/", e)
|
|
||||||
assert.Equal(http.StatusNotFound, c)
|
|
||||||
|
|
||||||
// Directory Redirect
|
|
||||||
e.Static("/", "_fixture")
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/folder", nil)
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
e.ServeHTTP(rec, req)
|
|
||||||
assert.Equal(http.StatusMovedPermanently, rec.Code)
|
|
||||||
assert.Equal("/folder/", rec.HeaderMap["Location"][0])
|
|
||||||
|
|
||||||
// Directory with index.html
|
|
||||||
e.Static("/", "_fixture")
|
|
||||||
c, r := request(http.MethodGet, "/", e)
|
|
||||||
assert.Equal(http.StatusOK, c)
|
|
||||||
assert.Equal(true, strings.HasPrefix(r, "<!doctype html>"))
|
|
||||||
|
|
||||||
// Sub-directory with index.html
|
|
||||||
c, r = request(http.MethodGet, "/folder/", e)
|
|
||||||
assert.Equal(http.StatusOK, c)
|
|
||||||
assert.Equal(true, strings.HasPrefix(r, "<!doctype html>"))
|
|
||||||
|
|
||||||
|
if tc.expectHeaderLocation != "" {
|
||||||
|
assert.Equal(t, tc.expectHeaderLocation, rec.Result().Header["Location"][0])
|
||||||
|
} else {
|
||||||
|
_, ok := rec.Result().Header["Location"]
|
||||||
|
assert.False(t, ok)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEchoFile(t *testing.T) {
|
func TestEchoFile(t *testing.T) {
|
||||||
|
@ -167,7 +167,7 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security
|
name := filepath.Join(config.Root, filepath.Clean("/"+p)) // "/"+ for security
|
||||||
|
|
||||||
if config.IgnoreBase {
|
if config.IgnoreBase {
|
||||||
routePath := path.Base(strings.TrimRight(c.Path(), "/*"))
|
routePath := path.Base(strings.TrimRight(c.Path(), "/*"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user