fix(security): redact database query parameters (HH-596) (#159)
Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
@@ -2,6 +2,8 @@ package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/postgres"
|
||||
@@ -16,7 +18,7 @@ import (
|
||||
// Pattern follows Chatwoot's ActiveRecord PostgreSQL setup in config/database.yml
|
||||
func NewDatabase(cfg *config.DatabaseConfig, logLevel string) (*gorm.DB, error) {
|
||||
dsn := cfg.DSN
|
||||
|
||||
|
||||
// Map log level to GORM logger level
|
||||
var gormLogLevel gormlogger.LogLevel
|
||||
switch logLevel {
|
||||
@@ -33,8 +35,8 @@ func NewDatabase(cfg *config.DatabaseConfig, logLevel string) (*gorm.DB, error)
|
||||
}
|
||||
|
||||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
|
||||
Logger: gormlogger.Default.LogMode(gormLogLevel),
|
||||
PrepareStmt: true,
|
||||
Logger: newDatabaseLogger(gormLogLevel),
|
||||
PrepareStmt: true,
|
||||
DisableForeignKeyConstraintWhenMigrating: true, // migrate first, add FK constraints later
|
||||
})
|
||||
if err != nil {
|
||||
@@ -58,3 +60,12 @@ func NewDatabase(cfg *config.DatabaseConfig, logLevel string) (*gorm.DB, error)
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func newDatabaseLogger(level gormlogger.LogLevel) gormlogger.Interface {
|
||||
return gormlogger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), gormlogger.Config{
|
||||
SlowThreshold: 200 * time.Millisecond,
|
||||
LogLevel: level,
|
||||
IgnoreRecordNotFoundError: true,
|
||||
ParameterizedQueries: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
gormlogger "gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
func TestDatabaseLoggerRedactsQueryParameters(t *testing.T) {
|
||||
filter, ok := newDatabaseLogger(gormlogger.Info).(gorm.ParamsFilter)
|
||||
require.True(t, ok)
|
||||
|
||||
sql, params := filter.ParamsFilter(context.Background(), "SELECT * FROM contact_inboxes WHERE pubsub_token = ?", "secret-token")
|
||||
require.Equal(t, "SELECT * FROM contact_inboxes WHERE pubsub_token = ?", sql)
|
||||
require.Empty(t, params)
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (h *Handler) ServeWS(c *gin.Context) {
|
||||
// Step 1: Authenticate (JWT or pubsub_token)
|
||||
claims, err := h.authenticator.Authenticate(c)
|
||||
if err != nil {
|
||||
logger.L().Errorf("ws: authentication failed: %v", err)
|
||||
logger.L().Warnf("ws: authentication rejected: %v", err)
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ func (a *WSAuthenticator) AuthenticateAndServeWS(c *gin.Context) {
|
||||
// Step 1: Authenticate
|
||||
claims, err := a.Authenticate(c)
|
||||
if err != nil {
|
||||
logger.L().Errorf("ws: authentication failed: %v", err)
|
||||
logger.L().Warnf("ws: authentication rejected: %v", err)
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user