forked from cloudwego/hertz
fix: fix path-traversal bug (#229)
This commit is contained in:
parent
690c346ee9
commit
dcb0b5a186
|
@ -28,6 +28,7 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
StrBackSlash = []byte("\\")
|
||||
StrSlash = []byte("/")
|
||||
StrSlashSlash = []byte("//")
|
||||
StrSlashDotDot = []byte("/..")
|
||||
|
|
|
@ -43,6 +43,7 @@ package protocol
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/cloudwego/hertz/internal/bytesconv"
|
||||
|
@ -318,9 +319,9 @@ func (u *URI) SetHostBytes(host []byte) {
|
|||
//
|
||||
// Examples:
|
||||
//
|
||||
// * For /foo/bar/baz.html path returns baz.html.
|
||||
// * For /foo/bar/ returns empty byte slice.
|
||||
// * For /foobar.js returns foobar.js.
|
||||
// - For /foo/bar/baz.html path returns baz.html.
|
||||
// - For /foo/bar/ returns empty byte slice.
|
||||
// - For /foobar.js returns foobar.js.
|
||||
func (u *URI) LastPathSegment() []byte {
|
||||
path := u.Path()
|
||||
n := bytes.LastIndexByte(path, '/')
|
||||
|
@ -334,14 +335,14 @@ func (u *URI) LastPathSegment() []byte {
|
|||
//
|
||||
// The following newURI types are accepted:
|
||||
//
|
||||
// * Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
|
||||
// uri is replaced by newURI.
|
||||
// * Absolute without scheme, i.e. //foobar.com/aaa/bb?cc. In this case
|
||||
// the original scheme is preserved.
|
||||
// * Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
|
||||
// of the original uri is replaced.
|
||||
// * Relative path, i.e. xx?yy=abc . In this case the original RequestURI
|
||||
// is updated according to the new relative path.
|
||||
// - Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
|
||||
// uri is replaced by newURI.
|
||||
// - Absolute without scheme, i.e. //foobar.com/aaa/bb?cc. In this case
|
||||
// the original scheme is preserved.
|
||||
// - Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
|
||||
// of the original uri is replaced.
|
||||
// - Relative path, i.e. xx?yy=abc . In this case the original RequestURI
|
||||
// is updated according to the new relative path.
|
||||
func (u *URI) Update(newURI string) {
|
||||
u.UpdateBytes(bytesconv.S2b(newURI))
|
||||
}
|
||||
|
@ -350,14 +351,14 @@ func (u *URI) Update(newURI string) {
|
|||
//
|
||||
// The following newURI types are accepted:
|
||||
//
|
||||
// * Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
|
||||
// uri is replaced by newURI.
|
||||
// * Absolute without scheme, i.e. //foobar.com/aaa/bb?cc. In this case
|
||||
// the original scheme is preserved.
|
||||
// * Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
|
||||
// of the original uri is replaced.
|
||||
// * Relative path, i.e. xx?yy=abc . In this case the original RequestURI
|
||||
// is updated according to the new relative path.
|
||||
// - Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
|
||||
// uri is replaced by newURI.
|
||||
// - Absolute without scheme, i.e. //foobar.com/aaa/bb?cc. In this case
|
||||
// the original scheme is preserved.
|
||||
// - Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
|
||||
// of the original uri is replaced.
|
||||
// - Relative path, i.e. xx?yy=abc . In this case the original RequestURI
|
||||
// is updated according to the new relative path.
|
||||
func (u *URI) UpdateBytes(newURI []byte) {
|
||||
u.requestURI = u.updateBytes(newURI, u.requestURI)
|
||||
}
|
||||
|
@ -484,6 +485,18 @@ func normalizePath(dst, src []byte) []byte {
|
|||
dst = addLeadingSlash(dst, src)
|
||||
dst = decodeArgAppendNoPlus(dst, src)
|
||||
|
||||
// Windows server need to replace all backslashes with
|
||||
// forward slashes to avoid path traversal attacks.
|
||||
if filepath.Separator == '\\' {
|
||||
for {
|
||||
n := bytes.IndexByte(dst, '\\')
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
dst[n] = '/'
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicate slashes
|
||||
b := dst
|
||||
bSize := len(b)
|
||||
|
|
|
@ -43,6 +43,7 @@ package protocol
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
@ -228,3 +229,20 @@ func testURIFullURI(t *testing.T, scheme, host, path, hash string, args *Args, e
|
|||
t.Fatalf("Unexpected URI: %q. Expected %q", uri, expectedURI)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePathWindows(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testParsePathWindows(t, "/../../../../../foo", "/foo")
|
||||
testParsePathWindows(t, "/..\\..\\..\\..\\..\\foo", "/foo")
|
||||
testParsePathWindows(t, "/..%5c..%5cfoo", "/foo")
|
||||
}
|
||||
|
||||
func testParsePathWindows(t *testing.T, path, expectedPath string) {
|
||||
var u URI
|
||||
u.Parse(nil, []byte(path))
|
||||
parsedPath := u.Path()
|
||||
if filepath.Separator == '\\' && string(parsedPath) != expectedPath {
|
||||
t.Fatalf("Unexpected Path: %q. Expected %q", parsedPath, expectedPath)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue