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)