mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 15:28:54 +00:00
security: Validate redirects against security.http.urls
A server allowed by security.http.urls could redirect resources.GetRemote to a host that is not. Re-run the check on each hop via CheckRedirect. Fixes #14871
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package create
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
@@ -97,6 +98,15 @@ func New(rs *resources.Spec) *Client {
|
||||
remoteResourceLogger: rs.Logger.InfoCommand("remote"),
|
||||
httpClient: &http.Client{
|
||||
Timeout: httpTimeout,
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
if err := rs.ExecHelper.Sec().CheckAllowedHTTPURL(req.URL.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(via) >= 10 {
|
||||
return errors.New("stopped after 10 redirects")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Transport: &httpcache.Transport{
|
||||
Cache: fileCache.AsHTTPCache(),
|
||||
CacheKey: func(req *http.Request) string {
|
||||
|
||||
@@ -276,6 +276,47 @@ urls = ['.*']
|
||||
})
|
||||
}
|
||||
|
||||
// Issue 14871.
|
||||
func TestGetRemoteRedirectSecurityCheckIssue14871(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Final server: the redirect target. Its host must be denied by security.http.urls.
|
||||
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", "text/plain")
|
||||
w.Write([]byte("should not reach here"))
|
||||
}))
|
||||
t.Cleanup(func() { target.Close() })
|
||||
|
||||
// Redirector: the allowed host. Redirects to the denied target.
|
||||
redirector := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, target.URL+"/", http.StatusFound)
|
||||
}))
|
||||
t.Cleanup(func() { redirector.Close() })
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
[security]
|
||||
[security.http]
|
||||
urls = ['REDIRECTOR']
|
||||
mediaTypes = ['text/plain']
|
||||
-- layouts/home.html --
|
||||
{{ $url := "REDIRECTOR/" }}
|
||||
{{ with try (resources.GetRemote $url) }}
|
||||
{{ with .Err }}
|
||||
Err: {{ . }}
|
||||
{{ else with .Value }}
|
||||
Content: {{ .Content }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
`
|
||||
files = strings.ReplaceAll(files, "REDIRECTOR", redirector.URL)
|
||||
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
b.AssertFileContent("public/index.html", "Err:", "security.http.urls")
|
||||
b.AssertFileContent("public/index.html", "! should not reach here")
|
||||
}
|
||||
|
||||
// Issue 14611.
|
||||
func TestGetRemotePerRequestTimeoutBodyRead(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
Reference in New Issue
Block a user