feat:add domain whitelist

#IJQNEX
This commit is contained in:
samwaf
2026-05-29 15:07:04 +08:00
parent d26e1afdc1
commit 7473206f24
8 changed files with 163 additions and 2 deletions
+60
View File
@@ -440,6 +440,66 @@ func (w *WafVpConfigApi) UpdateNoticeTitleApi(c *gin.Context) {
response.OkWithDetailed(resp, "更新通知标题成功", c)
}
// GetDomainWhitelistApi 获取管理端域名白名单
// @Summary 获取管理端域名白名单
// @Description 获取当前管理端允许访问的域名白名单配置
// @Tags 管理端配置
// @Accept json
// @Produce json
// @Success 200 {object} response.Response "获取域名白名单成功"
// @Security ApiKeyAuth
// @Router /vipconfig/getDomainWhitelist [get]
func (w *WafVpConfigApi) GetDomainWhitelistApi(c *gin.Context) {
resp := response2.WafVpConfigDomainWhitelistGetResp{
DomainWhitelist: global.GWAF_DOMAIN_WHITELIST,
}
response.OkWithDetailed(resp, "获取域名白名单成功", c)
}
// UpdateDomainWhitelistApi 更新管理端域名白名单
// @Summary 更新管理端域名白名单
// @Description 更新管理端允许访问的域名白名单(多个域名用逗号分隔,为空表示不限制)
// @Tags 管理端配置
// @Accept json
// @Produce json
// @Param data body request.WafVpConfigDomainWhitelistUpdateReq true "域名白名单配置"
// @Success 200 {object} response.Response "更新域名白名单成功"
// @Security ApiKeyAuth
// @Router /vipconfig/updateDomainWhitelist [post]
func (w *WafVpConfigApi) UpdateDomainWhitelistApi(c *gin.Context) {
var req request.WafVpConfigDomainWhitelistUpdateReq
if err := c.ShouldBindJSON(&req); err != nil {
response.FailWithMessage("解析请求失败", c)
return
}
// 若白名单非空,当前访问域名必须在列表中,防止把自己锁在外面
if strings.TrimSpace(req.DomainWhitelist) != "" {
host := c.Request.Host
hostname, _, err := net.SplitHostPort(host)
if err != nil {
hostname = host
}
selfIncluded := false
for _, d := range strings.Split(req.DomainWhitelist, ",") {
if strings.TrimSpace(d) == hostname {
selfIncluded = true
break
}
}
if !selfIncluded {
response.FailWithMessage(fmt.Sprintf("当前访问域名(%s)不在新白名单中,保存后将无法访问管理端,请先将当前域名加入白名单", hostname), c)
return
}
}
if err := wafconfig.UpdateDomainWhitelist(req.DomainWhitelist); err != nil {
response.FailWithMessage("更新域名白名单失败: "+err.Error(), c)
} else {
response.OkWithMessage("更新域名白名单成功", c)
}
}
// RestartManagerApi 重启管理端
// @Summary 重启管理端
// @Description 触发管理端1秒后重启,请等待5-10秒后重新访问
+1
View File
@@ -77,6 +77,7 @@ var (
//管理端访问控制
GWAF_IP_WHITELIST string = "0.0.0.0/0,::/0" //IP白名单 后台默认放行所有
GWAF_DOMAIN_WHITELIST string = "" //域名白名单,为空时不限制,多个用逗号分隔
GWAF_SSL_ENABLE bool = false //是否启用SSL证书
GWAF_SECURITY_ENTRY_ENABLE bool = false //是否启用安全路径入口
GWAF_SECURITY_ENTRY_PATH string = "" //安全路径(18位随机码)
+38
View File
@@ -0,0 +1,38 @@
package middleware
import (
"SamWaf/global"
"github.com/gin-gonic/gin"
"net"
"net/http"
"strings"
)
// DomainWhitelist 域名白名单中间件
// 为空时不限制;非空时仅允许 Host 匹配的域名访问(忽略端口)。
func DomainWhitelist() gin.HandlerFunc {
return func(c *gin.Context) {
whitelist := strings.TrimSpace(global.GWAF_DOMAIN_WHITELIST)
if whitelist == "" {
c.Next()
return
}
host := c.Request.Host
hostname, _, err := net.SplitHostPort(host)
if err != nil {
hostname = host
}
for _, domain := range strings.Split(whitelist, ",") {
if strings.TrimSpace(domain) == hostname {
c.Next()
return
}
}
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"message": "Access denied",
})
}
}
+5
View File
@@ -26,3 +26,8 @@ type WafVpConfigSecurityEntryUpdateReq struct {
type WafVpConfigNoticeTitleUpdateReq struct {
NoticeTitle string `json:"notice_title"` // 通知消息标题前缀,用于区分多实例
}
// WafVpConfigDomainWhitelistUpdateReq 域名白名单更新请求
type WafVpConfigDomainWhitelistUpdateReq struct {
DomainWhitelist string `json:"domain_whitelist"` // 多个域名用逗号分隔,为空表示不限制
}
+5
View File
@@ -25,3 +25,8 @@ type WafVpConfigSecurityEntryGetResp struct {
type WafVpConfigNoticeTitleGetResp struct {
NoticeTitle string `json:"notice_title"` // 通知消息标题前缀
}
// WafVpConfigDomainWhitelistGetResp 域名白名单获取响应
type WafVpConfigDomainWhitelistGetResp struct {
DomainWhitelist string `json:"domain_whitelist"`
}
+2
View File
@@ -22,4 +22,6 @@ func (receiver *WafVpConfigRouter) InitWafVpConfigRouter(group *gin.RouterGroup)
router.POST("/api/v1/vipconfig/updateSecurityEntry", wafVpConfigApi.UpdateSecurityEntryApi)
router.GET("/api/v1/vipconfig/getNoticeTitle", wafVpConfigApi.GetNoticeTitleApi)
router.POST("/api/v1/vipconfig/updateNoticeTitle", wafVpConfigApi.UpdateNoticeTitleApi)
router.GET("/api/v1/vipconfig/getDomainWhitelist", wafVpConfigApi.GetDomainWhitelistApi)
router.POST("/api/v1/vipconfig/updateDomainWhitelist", wafVpConfigApi.UpdateDomainWhitelistApi)
}
+50
View File
@@ -155,6 +155,14 @@ func LoadAndInitConfig() {
configChanged = true
}
//配置和提取域名白名单
if config.IsSet("security.domain_whitelist") {
global.GWAF_DOMAIN_WHITELIST = config.GetString("security.domain_whitelist")
} else {
config.Set("security.domain_whitelist", global.GWAF_DOMAIN_WHITELIST)
configChanged = true
}
//配置和提取SSL启用状态
if config.IsSet("security.ssl_enable") {
global.GWAF_SSL_ENABLE = config.GetBool("security.ssl_enable")
@@ -355,6 +363,48 @@ func UpdateIpWhitelist(ipWhitelist string) error {
return nil
}
// UpdateDomainWhitelist 更新域名白名单配置
func UpdateDomainWhitelist(domainWhitelist string) error {
currentTime := time.Now().Format("2006-01-02 15:04:05.000")
configDir := utils.GetCurrentDir() + "/conf/"
if _, err := os.Stat(configDir); os.IsNotExist(err) {
if err := os.MkdirAll(configDir, os.ModePerm); err != nil {
fmt.Printf("%s\tERROR\t创建config目录失败:%v\n", currentTime, err)
return err
}
}
config := viper.New()
config.AddConfigPath(configDir)
config.SetConfigName("config")
config.SetConfigType("yml")
if err := config.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
fmt.Printf("%s\tWARN\t找不到配置文件..\n", currentTime)
config.Set("local_port", global.GWAF_LOCAL_SERVER_PORT)
if err = config.SafeWriteConfig(); err != nil {
return err
}
} else {
fmt.Printf("%s\tERROR\t配置文件出错..\n", currentTime)
return err
}
}
config.Set("security.domain_whitelist", domainWhitelist)
global.GWAF_DOMAIN_WHITELIST = domainWhitelist
if err := config.WriteConfig(); err != nil {
fmt.Printf("%s\tERROR\twrite config failed:%v\n", currentTime, err)
return err
}
fmt.Printf("%s\tINFO\tDomain whitelist config updated\n", currentTime)
return nil
}
// UpdateSslEnable 更新SSL启用状态配置
func UpdateSslEnable(sslEnable bool) error {
// 格式化当前时间为指定格式
+2 -2
View File
@@ -98,12 +98,12 @@ func (h *securityPathHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
func (web *WafWebManager) initRouter(r *gin.Engine) {
PublicRouterGroup := r.Group("")
PublicRouterGroup.Use(middleware.SecApi(), middleware.IPWhitelist(), middleware.ReplayProtect())
PublicRouterGroup.Use(middleware.SecApi(), middleware.IPWhitelist(), middleware.DomainWhitelist(), middleware.ReplayProtect())
router.PublicApiGroupApp.InitLoginRouter(PublicRouterGroup)
router.PublicApiGroupApp.InitCenterRouter(PublicRouterGroup) //注册中心接收接口
RouterGroup := r.Group("")
RouterGroup.Use(middleware.Auth(), middleware.ReplayProtect(), middleware.OpenApiLogMiddleware(), middleware.CenterApi(), middleware.SecApi(), middleware.GinGlobalExceptionMiddleWare(), middleware.IPWhitelist()) //TODO 中心管控 特定
RouterGroup.Use(middleware.Auth(), middleware.ReplayProtect(), middleware.OpenApiLogMiddleware(), middleware.CenterApi(), middleware.SecApi(), middleware.GinGlobalExceptionMiddleWare(), middleware.IPWhitelist(), middleware.DomainWhitelist()) //TODO 中心管控 特定
{
router.ApiGroupApp.InitHostRouter(RouterGroup)
router.ApiGroupApp.InitLogRouter(RouterGroup)