Browse Source

feat(security): 为敏感接口添加IP白名单保护

- 新增IP白名单中间件,用于限制只有指定IP可以访问敏感接口
- 在http.go中为GameShield相关接口添加IP白名单保护
- 更新local.yml配置文件,添加IP白名单配置项
- 新增ip_whitelist.go文件,实现IP白名单功能
fusu 2 months ago
parent
commit
cccfdd78b8
3 changed files with 147 additions and 28 deletions
  1. 8 0
      config/local.yml
  2. 105 0
      internal/middleware/ip_whitelist.go
  3. 34 28
      internal/server/http.go

+ 8 - 0
config/local.yml

@@ -63,3 +63,11 @@ limiter:
     register:      # 注册接口限流
       capacity: 50
       fillRate: 5
+
+# IP白名单配置
+ip_allowlist:
+  enabled: true    # 是否启用IP白名单
+  ips:             # 允许访问的IP列表
+    - 127.0.0.1    # 本地开发
+    - ::1          # IPv6本地回环地址
+    - 183.136.132.25  # 示例局域网IP

+ 105 - 0
internal/middleware/ip_whitelist.go

@@ -0,0 +1,105 @@
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"github.com/spf13/viper"
+	"go.uber.org/zap"
+	"net/http"
+	"sync"
+)
+
+// IPAllowlist 保存允许访问的IP列表
+type IPAllowlist struct {
+	allowedIPs map[string]bool
+	enabled    bool
+	mu         sync.RWMutex
+	logger     *log.Logger
+}
+
+// NewIPAllowlist 创建一个新的IP白名单实例
+func NewIPAllowlist(conf *viper.Viper, logger *log.Logger) *IPAllowlist {
+	allowedIPs := conf.GetStringSlice("ip_allowlist.ips")
+	enabled := conf.GetBool("ip_allowlist.enabled")
+
+	allowlist := &IPAllowlist{
+		allowedIPs: make(map[string]bool),
+		enabled:    enabled,
+		logger:     logger,
+	}
+
+	// 将配置文件中的IP添加到白名单
+	for _, ip := range allowedIPs {
+		allowlist.allowedIPs[ip] = true
+	}
+
+	return allowlist
+}
+
+// IPAllowlistMiddleware 创建一个IP白名单中间件
+func (a *IPAllowlist) IPAllowlistMiddleware() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		// 如果白名单未启用,直接放行
+		if !a.enabled {
+			c.Next()
+			return
+		}
+
+		clientIP := getClientIP(c.Request)
+		a.mu.RLock()
+		_, allowed := a.allowedIPs[clientIP]
+		a.mu.RUnlock()
+
+		if allowed {
+			c.Next()
+		} else {
+			a.logger.WithContext(c).Warn("拒绝未授权的IP访问: %s", zap.String("ip", clientIP))
+			c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
+				"code": 403,
+				"msg":  "IP访问受限,您的IP没有权限访问此资源",
+			})
+		}
+	}
+}
+
+// AddIP 添加IP到白名单
+func (a *IPAllowlist) AddIP(ip string) {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+	a.allowedIPs[ip] = true
+}
+
+// RemoveIP 从白名单中移除IP
+func (a *IPAllowlist) RemoveIP(ip string) {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+	delete(a.allowedIPs, ip)
+}
+
+// IsIPAllowed 检查IP是否在白名单中
+func (a *IPAllowlist) IsIPAllowed(ip string) bool {
+	a.mu.RLock()
+	defer a.mu.RUnlock()
+	return a.allowedIPs[ip]
+}
+
+// EnableAllowlist 启用IP白名单
+func (a *IPAllowlist) EnableAllowlist() {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+	a.enabled = true
+}
+
+// DisableAllowlist 禁用IP白名单
+func (a *IPAllowlist) DisableAllowlist() {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+	a.enabled = false
+}
+
+// IsEnabled 检查白名单是否启用
+func (a *IPAllowlist) IsEnabled() bool {
+	a.mu.RLock()
+	defer a.mu.RUnlock()
+	return a.enabled
+}

+ 34 - 28
internal/server/http.go

@@ -77,34 +77,40 @@ func NewHTTPServer(
 			// 注册API限流
 			registerConfig := limiterInstance.GetAPIConfig("register")
 			noAuthRouter.POST("/register", middleware.IPRateLimitMiddleware(registerConfig), userHandler.Register)
-			noAuthRouter.POST("/gameShield/add", gameShieldHandler.SubmitGameShield)
-			noAuthRouter.POST("/gameShield/getField", gameShieldHandler.GetGameShieldField)
-			noAuthRouter.POST("/gameShield/getKey", gameShieldHandler.GetGameShieldKey)
-			noAuthRouter.POST("/gameShield/edit", gameShieldHandler.EditGameShield)
-			noAuthRouter.POST("/gameShield/delete", gameShieldHandler.DeleteGameShield)
-			noAuthRouter.POST("/gameShield/getOnline", gameShieldHandler.GetGameShieldOnlineList)
-			noAuthRouter.POST("/gameShield/IsExistKey", gameShieldHandler.IsExistGameShieldKey)
-			noAuthRouter.POST("/webForward/add", webForwardingHandler.AddWebForwarding)
-			noAuthRouter.POST("/webForward/edit", webForwardingHandler.EditWebForwarding)
-			noAuthRouter.POST("/webForward/delete", webForwardingHandler.DeleteWebForwarding)
-			noAuthRouter.POST("/webLimit/add", weblimitHandler.AddWebLimit)
-			noAuthRouter.POST("/webLimit/edit", weblimitHandler.EditWebLimit)
-			noAuthRouter.POST("/webLimit/delete", weblimitHandler.DeleteWebLimit)
-			noAuthRouter.POST("/tcpForward/add", tcpForwardingHandler.AddTcpForwarding)
-			noAuthRouter.POST("/tcpForward/edit", tcpForwardingHandler.EditTcpForwarding)
-			noAuthRouter.POST("/tcpForward/delete", tcpForwardingHandler.DeleteTcpForwarding)
-			noAuthRouter.POST("/udpForward/add", udpForwardingHandler.AddUdpForWarding)
-			noAuthRouter.POST("/udpForward/edit", udpForwardingHandler.EditUdpForWarding)
-			noAuthRouter.POST("/udpForward/delete", udpForwardingHandler.DeleteUdpForWarding)
-			noAuthRouter.POST("/tcpLimit/add", tcpLimitHandler.AddTcpLimit)
-			noAuthRouter.POST("/tcpLimit/edit", tcpLimitHandler.EditTcpLimit)
-			noAuthRouter.POST("/tcpLimit/delete", tcpLimitHandler.DeleteTcpLimit)
-			noAuthRouter.POST("/udpLimit/add", udpLimitHandler.AddUdpLimit)
-			noAuthRouter.POST("/udpLimit/edit", udpLimitHandler.EditUdpLimit)
-			noAuthRouter.POST("/udpLimit/delete", udpLimitHandler.DeleteUdpLimit)
-			noAuthRouter.POST("/gameShieldBackend/add", gameShieldBackendHandler.AddGameShieldBackend)
-			noAuthRouter.POST("/gameShieldBackend/edit", gameShieldBackendHandler.EditGameShieldBackend)
-			noAuthRouter.POST("/gameShieldBackend/delete", gameShieldBackendHandler.DeleteGameShieldBackend)
+
+			// 创建IP白名单实例
+			ipAllowlist := middleware.NewIPAllowlist(conf, logger)
+			ipAllowlistMiddleware := ipAllowlist.IPAllowlistMiddleware()
+
+			// 为GameShield相关接口添加IP白名单保护
+			noAuthRouter.POST("/gameShield/add", ipAllowlistMiddleware, gameShieldHandler.SubmitGameShield)
+			noAuthRouter.POST("/gameShield/getField", ipAllowlistMiddleware, gameShieldHandler.GetGameShieldField)
+			noAuthRouter.POST("/gameShield/getKey", ipAllowlistMiddleware, gameShieldHandler.GetGameShieldKey)
+			noAuthRouter.POST("/gameShield/edit", ipAllowlistMiddleware, gameShieldHandler.EditGameShield)
+			noAuthRouter.POST("/gameShield/delete", ipAllowlistMiddleware, gameShieldHandler.DeleteGameShield)
+			noAuthRouter.POST("/gameShield/getOnline", ipAllowlistMiddleware, gameShieldHandler.GetGameShieldOnlineList)
+			noAuthRouter.POST("/gameShield/IsExistKey", ipAllowlistMiddleware, gameShieldHandler.IsExistGameShieldKey)
+			noAuthRouter.POST("/webForward/add", ipAllowlistMiddleware, webForwardingHandler.AddWebForwarding)
+			noAuthRouter.POST("/webForward/edit", ipAllowlistMiddleware, webForwardingHandler.EditWebForwarding)
+			noAuthRouter.POST("/webForward/delete", ipAllowlistMiddleware, webForwardingHandler.DeleteWebForwarding)
+			noAuthRouter.POST("/webLimit/add", ipAllowlistMiddleware, weblimitHandler.AddWebLimit)
+			noAuthRouter.POST("/webLimit/edit", ipAllowlistMiddleware, weblimitHandler.EditWebLimit)
+			noAuthRouter.POST("/webLimit/delete", ipAllowlistMiddleware, weblimitHandler.DeleteWebLimit)
+			noAuthRouter.POST("/tcpForward/add", ipAllowlistMiddleware, tcpForwardingHandler.AddTcpForwarding)
+			noAuthRouter.POST("/tcpForward/edit", ipAllowlistMiddleware, tcpForwardingHandler.EditTcpForwarding)
+			noAuthRouter.POST("/tcpForward/delete", ipAllowlistMiddleware, tcpForwardingHandler.DeleteTcpForwarding)
+			noAuthRouter.POST("/udpForward/add", ipAllowlistMiddleware, udpForwardingHandler.AddUdpForWarding)
+			noAuthRouter.POST("/udpForward/edit", ipAllowlistMiddleware, udpForwardingHandler.EditUdpForWarding)
+			noAuthRouter.POST("/udpForward/delete", ipAllowlistMiddleware, udpForwardingHandler.DeleteUdpForWarding)
+			noAuthRouter.POST("/tcpLimit/add", ipAllowlistMiddleware, tcpLimitHandler.AddTcpLimit)
+			noAuthRouter.POST("/tcpLimit/edit", ipAllowlistMiddleware, tcpLimitHandler.EditTcpLimit)
+			noAuthRouter.POST("/tcpLimit/delete", ipAllowlistMiddleware, tcpLimitHandler.DeleteTcpLimit)
+			noAuthRouter.POST("/udpLimit/add", ipAllowlistMiddleware, udpLimitHandler.AddUdpLimit)
+			noAuthRouter.POST("/udpLimit/edit", ipAllowlistMiddleware, udpLimitHandler.EditUdpLimit)
+			noAuthRouter.POST("/udpLimit/delete", ipAllowlistMiddleware, udpLimitHandler.DeleteUdpLimit)
+			noAuthRouter.POST("/gameShieldBackend/add", ipAllowlistMiddleware, gameShieldBackendHandler.AddGameShieldBackend)
+			noAuthRouter.POST("/gameShieldBackend/edit", ipAllowlistMiddleware, gameShieldBackendHandler.EditGameShieldBackend)
+			noAuthRouter.POST("/gameShieldBackend/delete", ipAllowlistMiddleware, gameShieldBackendHandler.DeleteGameShieldBackend)
 		}
 		// Non-strict permission routing group
 		noStrictAuthRouter := v1.Group("/").Use(middleware.NoStrictAuth(jwt, logger))