1
1
mirror of https://github.com/go-gitea/gitea synced 2025-08-09 11:08:19 +00:00

Only allow webhook to send requests to allowed hosts (#17482) (#17510)

Backport #17482

* Only allow webhook to send requests to allowed hosts (backport #17482)

* use ALLOWED_HOST_LIST=* for default to keep the legacy behavior in 1.15.x
This commit is contained in:
wxiaoguang
2021-11-06 17:23:43 +08:00
committed by GitHub
parent 15b44496ec
commit 20ae184967
9 changed files with 285 additions and 26 deletions

View File

@@ -20,6 +20,7 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"time"
"code.gitea.io/gitea/models"
@@ -29,6 +30,8 @@ import (
"github.com/gobwas/glob"
)
var contextKeyWebhookRequest interface{} = "contextKeyWebhookRequest"
// Deliver deliver hook task
func Deliver(t *models.HookTask) error {
w, err := models.GetWebhookByID(t.HookID)
@@ -166,7 +169,7 @@ func Deliver(t *models.HookTask) error {
return fmt.Errorf("Webhook task skipped (webhooks disabled): [%d]", t.ID)
}
resp, err := webhookHTTPClient.Do(req)
resp, err := webhookHTTPClient.Do(req.WithContext(context.WithValue(req.Context(), contextKeyWebhookRequest, req)))
if err != nil {
t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err)
return err
@@ -288,14 +291,29 @@ func InitDeliverHooks() {
timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second
webhookHTTPClient = &http.Client{
Timeout: timeout,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify},
Proxy: webhookProxy(),
Dial: func(netw, addr string) (net.Conn, error) {
return net.DialTimeout(netw, addr, timeout) // dial timeout
DialContext: func(ctx context.Context, network, addrOrHost string) (net.Conn, error) {
dialer := net.Dialer{
Timeout: timeout,
Control: func(network, ipAddr string, c syscall.RawConn) error {
// in Control func, the addr was already resolved to IP:PORT format, there is no cost to do ResolveTCPAddr here
tcpAddr, err := net.ResolveTCPAddr(network, ipAddr)
req := ctx.Value(contextKeyWebhookRequest).(*http.Request)
if err != nil {
return fmt.Errorf("webhook can only call HTTP servers via TCP, deny '%s(%s:%s)', err=%v", req.Host, network, ipAddr, err)
}
if !setting.Webhook.AllowedHostList.MatchesHostOrIP(req.Host, tcpAddr.IP) {
return fmt.Errorf("webhook can only call allowed HTTP servers (check your webhook.ALLOWED_HOST_LIST setting), deny '%s(%s)'", req.Host, ipAddr)
}
return nil
},
}
return dialer.DialContext(ctx, network, addrOrHost)
},
},
Timeout: timeout, // request timeout
}
go graceful.GetManager().RunWithShutdownContext(DeliverHooks)