Immplemented limiting client IP to first that requests a challenge

This commit is contained in:
Samuel Hawksby-Robinson 2023-03-20 22:01:28 +00:00
parent 231ded6a7b
commit 43c2bc24d7
2 changed files with 63 additions and 1 deletions

View File

@ -5,6 +5,7 @@ import (
"crypto/rand"
"fmt"
"io/ioutil"
"net"
"net/http"
"github.com/btcsuite/btcutil/base58"
@ -48,6 +49,7 @@ type ChallengeGiver struct {
cookieStore *sessions.CookieStore
encryptor *PayloadEncryptor
logger *zap.Logger
authedIP net.IP
}
func NewChallengeGiver(e *PayloadEncryptor, logger *zap.Logger) (*ChallengeGiver, error) {
@ -63,6 +65,50 @@ func NewChallengeGiver(e *PayloadEncryptor, logger *zap.Logger) (*ChallengeGiver
}, nil
}
func (cg *ChallengeGiver) getIP(r *http.Request) (net.IP, *ChallengeError) {
h, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
cg.logger.Error("getIP: h, _, err := net.SplitHostPort(r.RemoteAddr)", zap.Error(err), zap.String("r.RemoteAddr", r.RemoteAddr))
return nil, &ChallengeError{"error", http.StatusInternalServerError}
}
return net.ParseIP(h), nil
}
func (cg *ChallengeGiver) registerClientIP(r *http.Request) *ChallengeError {
hIP, err := cg.getIP(r)
if err != nil {
return err
}
cg.authedIP = hIP
return nil
}
func (cg *ChallengeGiver) validateClientIP(r *http.Request) *ChallengeError {
// If we haven't registered yet register the IP
if cg.authedIP == nil || len(cg.authedIP) == 0 {
err := cg.registerClientIP(r)
if err != nil {
return err
}
}
// Then compare the current req RemoteIP with the authed IP
hIP, err := cg.getIP(r)
if err != nil {
return err
}
if !cg.authedIP.Equal(hIP) {
cg.logger.Error(
"request RemoteAddr does not match authedIP: expected '%s', received '%s'",
zap.String("expected", cg.authedIP.String()),
zap.String("received", hIP.String()),
)
return &ChallengeError{"forbidden", http.StatusForbidden}
}
return nil
}
func (cg *ChallengeGiver) getSession(r *http.Request) (*sessions.Session, *ChallengeError) {
s, err := cg.cookieStore.Get(r, sessionChallenge)
if err != nil {
@ -102,6 +148,11 @@ func (cg *ChallengeGiver) block(s *sessions.Session, w http.ResponseWriter, r *h
}
func (cg *ChallengeGiver) checkChallengeResponse(w http.ResponseWriter, r *http.Request) *ChallengeError {
ce := cg.validateClientIP(r)
if ce != nil {
return ce
}
s, ce := cg.getSession(r)
if ce != nil {
return ce
@ -136,12 +187,17 @@ func (cg *ChallengeGiver) checkChallengeResponse(w http.ResponseWriter, r *http.
return cg.block(s, w, r)
}
// If every is ok, regenerate the challenge
// If every is ok, generate a new challenge for the next req
_, ce = cg.generateNewChallenge(s, w, r)
return ce
}
func (cg *ChallengeGiver) getChallenge(w http.ResponseWriter, r *http.Request) ([]byte, *ChallengeError) {
err := cg.validateClientIP(r)
if err != nil {
return nil, err
}
s, err := cg.getSession(r)
if err != nil {
return nil, err

View File

@ -192,6 +192,12 @@ func (c *SenderClient) receiveInstallationData() error {
return err
}
err = c.challengeTaker.DoChallenge(req)
if err != nil {
signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
return err
}
resp, err := c.Do(req)
if err != nil {
signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})