Skip to content

Commit

Permalink
server: disable redirects in peer communication
Browse files Browse the repository at this point in the history
Disable following redirects from peer HTTP communication on the client's side.
Etcd server may run into SSRF (Server-side request forgery) when adding a new
member. If users provide a malicious peer URL, the existing etcd members may be
redirected to another unexpected internal URL when getting the new member's
version.

Signed-off-by: Ivan Valdes <ivan@vald.es>
  • Loading branch information
ivanvc committed Dec 5, 2023
1 parent ce4ae2b commit 98aa466
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 4 deletions.
13 changes: 12 additions & 1 deletion server/etcdserver/cluster_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ func getClusterFromRemotePeers(lg *zap.Logger, urls []string, timeout time.Durat
cc := &http.Client{
Transport: rt,
Timeout: timeout,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
for _, u := range urls {
addr := u + "/members"
Expand Down Expand Up @@ -324,7 +327,12 @@ func getVersion(lg *zap.Logger, m *membership.Member, rt http.RoundTripper) (*ve
}

func promoteMemberHTTP(ctx context.Context, url string, id uint64, peerRt http.RoundTripper) ([]*membership.Member, error) {
cc := &http.Client{Transport: peerRt}
cc := &http.Client{
Transport: peerRt,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
// TODO: refactor member http handler code
// cannot import etcdhttp, so manually construct url
requestUrl := url + "/members/promote/" + fmt.Sprintf("%d", id)
Expand Down Expand Up @@ -396,6 +404,9 @@ func getDowngradeEnabledFromRemotePeers(lg *zap.Logger, cl *membership.RaftClust
func getDowngradeEnabled(lg *zap.Logger, m *membership.Member, rt http.RoundTripper) (bool, error) {
cc := &http.Client{
Transport: rt,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
var (
err error
Expand Down
7 changes: 6 additions & 1 deletion server/etcdserver/corrupt.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,12 @@ func (s *EtcdServer) getPeerHashKVs(rev int64) []*peerHashKVResp {

lg := s.Logger()

cc := &http.Client{Transport: s.peerRt}
cc := &http.Client{
Transport: s.peerRt,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
var resps []*peerHashKVResp
for _, p := range peers {
if len(p.eps) == 0 {
Expand Down
14 changes: 12 additions & 2 deletions server/lease/leasehttp/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,12 @@ func RenewHTTP(ctx context.Context, id lease.LeaseID, url string, rt http.RoundT
return -1, err
}

cc := &http.Client{Transport: rt}
cc := &http.Client{
Transport: rt,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
req, err := http.NewRequest("POST", url, bytes.NewReader(lreq))
if err != nil {
return -1, err
Expand Down Expand Up @@ -210,7 +215,12 @@ func TimeToLiveHTTP(ctx context.Context, id lease.LeaseID, keys bool, url string

req = req.WithContext(ctx)

cc := &http.Client{Transport: rt}
cc := &http.Client{
Transport: rt,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
var b []byte
// buffer errc channel so that errc don't block inside the go routinue
resp, err := cc.Do(req)
Expand Down

0 comments on commit 98aa466

Please sign in to comment.