mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-05-20 17:00:24 +00:00
Use hostmatcher
to replace matchlist
, improve security (#17605)
Use hostmacher to replace matchlist. And we introduce a better DialContext to do a full host/IP check, otherwise the attackers can still bypass the allow/block list by a 302 redirection.
This commit is contained in:
parent
c96be0cd98
commit
013fb73068
33 changed files with 377 additions and 293 deletions
|
@ -13,17 +13,16 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
webhook_model "code.gitea.io/gitea/models/webhook"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/hostmatcher"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/proxy"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
@ -31,8 +30,6 @@ import (
|
|||
"github.com/gobwas/glob"
|
||||
)
|
||||
|
||||
var contextKeyWebhookRequest interface{} = "contextKeyWebhookRequest"
|
||||
|
||||
// Deliver deliver hook task
|
||||
func Deliver(t *webhook_model.HookTask) error {
|
||||
w, err := webhook_model.GetWebhookByID(t.HookID)
|
||||
|
@ -98,10 +95,10 @@ func Deliver(t *webhook_model.HookTask) error {
|
|||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, w.HTTPMethod)
|
||||
return fmt.Errorf("invalid http method for webhook: [%d] %v", t.ID, w.HTTPMethod)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, w.HTTPMethod)
|
||||
return fmt.Errorf("invalid http method for webhook: [%d] %v", t.ID, w.HTTPMethod)
|
||||
}
|
||||
|
||||
var signatureSHA1 string
|
||||
|
@ -172,10 +169,10 @@ func Deliver(t *webhook_model.HookTask) error {
|
|||
}()
|
||||
|
||||
if setting.DisableWebhooks {
|
||||
return fmt.Errorf("Webhook task skipped (webhooks disabled): [%d]", t.ID)
|
||||
return fmt.Errorf("webhook task skipped (webhooks disabled): [%d]", t.ID)
|
||||
}
|
||||
|
||||
resp, err := webhookHTTPClient.Do(req.WithContext(context.WithValue(req.Context(), contextKeyWebhookRequest, req)))
|
||||
resp, err := webhookHTTPClient.Do(req.WithContext(graceful.GetManager().ShutdownContext()))
|
||||
if err != nil {
|
||||
t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err)
|
||||
return err
|
||||
|
@ -296,29 +293,18 @@ func webhookProxy() func(req *http.Request) (*url.URL, error) {
|
|||
func InitDeliverHooks() {
|
||||
timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second
|
||||
|
||||
allowedHostListValue := setting.Webhook.AllowedHostList
|
||||
if allowedHostListValue == "" {
|
||||
allowedHostListValue = hostmatcher.MatchBuiltinExternal
|
||||
}
|
||||
allowedHostMatcher := hostmatcher.ParseHostMatchList("webhook.ALLOWED_HOST_LIST", allowedHostListValue)
|
||||
|
||||
webhookHTTPClient = &http.Client{
|
||||
Timeout: timeout,
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify},
|
||||
Proxy: webhookProxy(),
|
||||
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)
|
||||
},
|
||||
DialContext: hostmatcher.NewDialContext("webhook", allowedHostMatcher, nil),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue