server: disable redirects in peer communication
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>
This commit is contained in:
@ -70,6 +70,9 @@ func getClusterFromRemotePeers(lg *zap.Logger, urls []string, timeout time.Durat
|
|||||||
cc := &http.Client{
|
cc := &http.Client{
|
||||||
Transport: rt,
|
Transport: rt,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, u := range urls {
|
for _, u := range urls {
|
||||||
addr := u + "/members"
|
addr := u + "/members"
|
||||||
@ -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) {
|
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
|
// TODO: refactor member http handler code
|
||||||
// cannot import etcdhttp, so manually construct url
|
// cannot import etcdhttp, so manually construct url
|
||||||
requestUrl := url + "/members/promote/" + fmt.Sprintf("%d", id)
|
requestUrl := url + "/members/promote/" + fmt.Sprintf("%d", id)
|
||||||
@ -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) {
|
func getDowngradeEnabled(lg *zap.Logger, m *membership.Member, rt http.RoundTripper) (bool, error) {
|
||||||
cc := &http.Client{
|
cc := &http.Client{
|
||||||
Transport: rt,
|
Transport: rt,
|
||||||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
},
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
|
@ -390,7 +390,12 @@ func (s *EtcdServer) getPeerHashKVs(rev int64) []*peerHashKVResp {
|
|||||||
|
|
||||||
lg := s.Logger()
|
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
|
var resps []*peerHashKVResp
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
if len(p.eps) == 0 {
|
if len(p.eps) == 0 {
|
||||||
|
@ -150,7 +150,12 @@ func RenewHTTP(ctx context.Context, id lease.LeaseID, url string, rt http.RoundT
|
|||||||
return -1, err
|
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))
|
req, err := http.NewRequest("POST", url, bytes.NewReader(lreq))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
@ -210,7 +215,12 @@ func TimeToLiveHTTP(ctx context.Context, id lease.LeaseID, keys bool, url string
|
|||||||
|
|
||||||
req = req.WithContext(ctx)
|
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
|
var b []byte
|
||||||
// buffer errc channel so that errc don't block inside the go routinue
|
// buffer errc channel so that errc don't block inside the go routinue
|
||||||
resp, err := cc.Do(req)
|
resp, err := cc.Do(req)
|
||||||
|
Reference in New Issue
Block a user