From 46afa417b70be56c92d469456eaca19a89650268 Mon Sep 17 00:00:00 2001 From: "$(pass /github/name)" <$(pass /github/email)> Date: Fri, 20 Sep 2024 07:57:54 +0200 Subject: [PATCH] xss mitigation & test --- internal/controllers/XSS_test.go | 31 ++++++++++++++++++++++ internal/models/bank_account.go | 4 +-- internal/models/consents.go | 8 +++--- internal/models/membership.go | 2 +- internal/models/subscription_model.go | 10 ++++---- internal/models/user.go | 22 ++++++++-------- internal/utils/validators.go | 37 +++++++++++++++++++-------- 7 files changed, 81 insertions(+), 33 deletions(-) create mode 100644 internal/controllers/XSS_test.go diff --git a/internal/controllers/XSS_test.go b/internal/controllers/XSS_test.go new file mode 100644 index 0000000..14cbdf4 --- /dev/null +++ b/internal/controllers/XSS_test.go @@ -0,0 +1,31 @@ +package controllers + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" +) + +func testXSSAttempt(t *testing.T) { + gin.SetMode(gin.TestMode) + router := gin.New() + router.POST("/register", Uc.RegisterUser) + + xssPayload := "" + user := getBaseUser() + user.FirstName = xssPayload + user.Email = "user@xss.hack" + jsonData, _ := json.Marshal(RegistrationData{User: user}) + req, _ := http.NewRequest("POST", "/register", bytes.NewBuffer(jsonData)) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusNotAcceptable, w.Code) + assert.NotContains(t, w.Body.String(), xssPayload) +} diff --git a/internal/models/bank_account.go b/internal/models/bank_account.go index a1f4b37..c42330b 100644 --- a/internal/models/bank_account.go +++ b/internal/models/bank_account.go @@ -6,8 +6,8 @@ type BankAccount struct { CreatedAt time.Time UpdatedAt time.Time MandateDateSigned time.Time `gorm:"not null"` // json:"mandate_date_signed"` - Bank string //`json:"bank_name" validate:"omitempty,alphanumunicode"` - AccountHolderName string //`json:"account_holder_name" validate:"omitempty,alphaunicode"` + Bank string //`json:"bank_name" validate:"omitempty,alphanumunicode,safe_content"` + AccountHolderName string //`json:"account_holder_name" validate:"omitempty,alphaunicode,safe_content"` IBAN string `gorm:"not null" json:"iban" validate:"required,iban"` BIC string //`json:"bic" validate:"omitempty,bic"` MandateReference string `gorm:"not null"` //json:"mandate_reference"` diff --git a/internal/models/consents.go b/internal/models/consents.go index c5bdcb0..9f068e6 100644 --- a/internal/models/consents.go +++ b/internal/models/consents.go @@ -5,10 +5,10 @@ import "time" type Consent struct { CreatedAt time.Time UpdatedAt time.Time - FirstName string `gorm:"not null" json:"first_name"` - LastName string `gorm:"not null" json:"last_name"` - Email string `json:"email"` - ConsentType string `gorm:"not null" json:"consent_type"` + FirstName string `gorm:"not null" json:"first_name" validate:"safe_content"` + LastName string `gorm:"not null" json:"last_name" validate:"safe_content"` + Email string `json:"email" validate:"email,safe_content"` + ConsentType string `gorm:"not null" json:"consent_type" validate:"safe_content"` ID int64 `gorm:"primaryKey"` UserID int64 `gorm:"not null" json:"user_id"` } diff --git a/internal/models/membership.go b/internal/models/membership.go index 60971a0..dae0019 100644 --- a/internal/models/membership.go +++ b/internal/models/membership.go @@ -7,7 +7,7 @@ type Membership struct { UpdatedAt time.Time StartDate time.Time `json:"start_date"` EndDate time.Time `json:"end_date"` - Status string `json:"status"` + Status string `json:"status" validate:"safe_content"` SubscriptionModel SubscriptionModel `gorm:"foreignKey:SubscriptionModelID" json:"subscription_model"` ParentMembershipID int64 `json:"parent_member_id" validate:"omitempty,omitnil,number"` SubscriptionModelID int64 `json:"subsription_model_id"` diff --git a/internal/models/subscription_model.go b/internal/models/subscription_model.go index 156611a..e0cb5d8 100644 --- a/internal/models/subscription_model.go +++ b/internal/models/subscription_model.go @@ -7,13 +7,13 @@ import ( type SubscriptionModel struct { CreatedAt time.Time UpdatedAt time.Time - Name string `json:"name" validate:"required,subscriptionModel"` + Name string `gorm:"unique" json:"name" validate:"required,subscriptionModel,safe_content"` Details string `json:"details" validate:"required"` Conditions string `json:"conditions"` RequiredMembershipField string `json:"required_membership_field" validate:"membershipField"` ID int64 `gorm:"primaryKey"` - MonthlyFee float32 `json:"monthly_fee" validate:"required,number"` - HourlyRate float32 `json:"hourly_rate" validate:"required,number"` - IncludedPerYear int16 `json:"included_hours_per_year" validate:"omitempty,number"` - IncludedPerMonth int16 `json:"included_hours_per_month" validate:"omitempty,number"` + MonthlyFee float32 `json:"monthly_fee" validate:"required,number,gte=0"` + HourlyRate float32 `json:"hourly_rate" validate:"required,number,gte=0"` + IncludedPerYear int16 `json:"included_hours_per_year" validate:"omitempty,number,gte=0"` + IncludedPerMonth int16 `json:"included_hours_per_month" validate:"omitempty,number,gte=0"` } diff --git a/internal/models/user.go b/internal/models/user.go index d593110..680d922 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -12,17 +12,17 @@ type User struct { UpdatedAt time.Time DateOfBirth time.Time `gorm:"not null" json:"date_of_birth" validate:"required,age"` CreatedAt time.Time - Company string `json:"company" validate:"omitempty,omitnil"` - Phone string `json:"phone" validate:"omitempty,omitnil"` - Notes *string `json:"notes"` - FirstName string `gorm:"not null" json:"first_name" validate:"required"` - Password string `json:"password" validate:"required_unless=RoleID 0"` - Email string `gorm:"unique;not null" json:"email" validate:"required,email"` - LastName string `gorm:"not null" json:"last_name" validate:"required"` - ProfilePicture string `json:"profile_picture" validate:"omitempty,omitnil,image"` - Address string `gorm:"not null" json:"address" validate:"required"` - ZipCode string `gorm:"not null" json:"zip_code" validate:"required,alphanum"` - City string `form:"not null" json:"city" validate:"required,alphaunicode"` + Company string `json:"company" validate:"omitempty,omitnil,safe_content"` + Phone string `json:"phone" validate:"omitempty,omitnil,safe_content"` + Notes *string `json:"notes,safe_content"` + FirstName string `gorm:"not null" json:"first_name" validate:"required,safe_content"` + Password string `json:"password" validate:"required_unless=RoleID 0,safe_content"` + Email string `gorm:"unique;not null" json:"email" validate:"required,email,safe_content"` + LastName string `gorm:"not null" json:"last_name" validate:"required,safe_content"` + ProfilePicture string `json:"profile_picture" validate:"omitempty,omitnil,image,safe_content"` + Address string `gorm:"not null" json:"address" validate:"required,safe_content"` + ZipCode string `gorm:"not null" json:"zip_code" validate:"required,alphanum,safe_content"` + City string `form:"not null" json:"city" validate:"required,alphaunicode,safe_content"` Consents []Consent `gorm:"constraint:OnUpdate:CASCADE"` BankAccount BankAccount `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"bank_account"` Verification Verification `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` diff --git a/internal/utils/validators.go b/internal/utils/validators.go index 0bcc131..cf102d6 100644 --- a/internal/utils/validators.go +++ b/internal/utils/validators.go @@ -7,7 +7,9 @@ import ( "GoMembership/internal/models" "GoMembership/pkg/logger" "reflect" + "regexp" "slices" + "strings" "time" "github.com/go-playground/validator/v10" @@ -15,19 +17,24 @@ import ( "github.com/jbub/banking/swift" ) -// -// func IsEmailValid(email string) bool { -// regex := `^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$` -// re := regexp.MustCompile(regex) -// return re.MatchString(email) -// } +var xssPatterns = []*regexp.Regexp{ + regexp.MustCompile(`(?i)