feat:well-known file

#323
This commit is contained in:
samwaf
2025-05-27 10:39:44 +08:00
parent 44394af8ae
commit 4eae3e0f9a
3 changed files with 45 additions and 32 deletions
+1
View File
@@ -18,6 +18,7 @@ var (
GCONFIG_RECORD_ENABLE_OWASP int64 = 0 //启动OWASP数据检测
GCONFIG_RECORD_ENABLE_HTTP_80 int64 = 0 //启动80端口服务(为自动申请证书使用 HTTP文件验证类型,DNS验证不需要)
GCONFIG_RECORD_SSLOrder_EXPIRE_DAY int64 = 30 // 提前多少天进行自动申请
GCONFIG_RECORD_SSLHTTP_CHECK int64 = 1 // ssl申请文件验证类型 是否校验原始路径HTTP响应代码 1 校验 0 不校验
GCONFIG_RECORD_CONNECT_TIME_OUT int64 = 30 // 连接超时 默认30s
GCONFIG_RECORD_KEEPALIVE_TIME_OUT int64 = 30 // 保持活动超时 默认30s
//GCONFIG_RECORD_PATCH_VERSION_CORE int64 = 20250106 // 核心数据库补丁日期
+40 -32
View File
@@ -451,7 +451,7 @@ func (waf *WafEngine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
if cacheConfig.IsEnableCache == 1 {
if cacheConfig.IsEnableCache == 1 && !strings.HasPrefix(weblogbean.URL, global.GSSL_HTTP_CHANGLE_PATH) {
cacheResp := wafwebcache.LoadWebDataFormCache(w, r, hostTarget, cacheConfig, &weblogbean)
if cacheResp != nil {
// 将缓存的响应写回给客户端
@@ -854,7 +854,7 @@ func (waf *WafEngine) modifyResponse() func(*http.Response) error {
if err != nil {
zlog.Debug("解析cache json失败")
}
if cacheConfig.IsEnableCache == 1 {
if cacheConfig.IsEnableCache == 1 && !strings.HasPrefix(weblogfrist.URL, global.GSSL_HTTP_CHANGLE_PATH) {
wafwebcache.StoreWebDataCache(resp, waf.HostTarget[host], cacheConfig, weblogfrist)
}
@@ -863,40 +863,48 @@ func (waf *WafEngine) modifyResponse() func(*http.Response) error {
datetimeNow := time.Now()
weblogfrist.TimeSpent = datetimeNow.UnixNano()/1e6 - weblogfrist.UNIX_ADD_TIME
if strings.HasPrefix(weblogfrist.URL, global.GSSL_HTTP_CHANGLE_PATH) && (resp.StatusCode == 404 || resp.StatusCode == 301 || resp.StatusCode == 302) {
//如果远端HTTP01不存在挑战验证文件,那么我们映射到走本地再试一下
// 根据配置决定是否检查HTTP响应代码并重定向到本地
if strings.HasPrefix(weblogfrist.URL, global.GSSL_HTTP_CHANGLE_PATH) {
if global.GCONFIG_RECORD_SSLHTTP_CHECK == 0 || resp.StatusCode == 404 || resp.StatusCode == 301 || resp.StatusCode == 302 {
//如果远端HTTP01不存在挑战验证文件,那么我们映射到走本地再试一下
//或者配置为不检查HTTP响应代码,直接走本地
//Challenge /.well-known/acme-challenge/2NKiiETgQdPmmjlM88mH5uo6jM98PrgWwsDslaN8
urls := strings.Split(weblogfrist.URL, "/")
if len(urls) == 4 {
challengeFile := urls[3]
//检测challengeFile是否合法
if !utils.IsValidChallengeFile(challengeFile) {
return nil
}
//当前路径 data/vhost/domain code 变量下
// 需要读取的文件路径
filePath := utils.GetCurrentDir() + "/data/vhost/" + weblogfrist.HOST_CODE + "/.well-known/acme-challenge/" + challengeFile
//Challenge /.well-known/acme-challenge/2NKiiETgQdPmmjlM88mH5uo6jM98PrgWwsDslaN8
urls := strings.Split(weblogfrist.URL, "/")
if len(urls) == 4 {
challengeFile := urls[3]
//检测challengeFile是否合法
if !utils.IsValidChallengeFile(challengeFile) {
return nil
}
//当前路径 data/vhost/domain code 变量下
// 需要读取的文件路径
filePath := utils.GetCurrentDir() + "/data/vhost/" + weblogfrist.HOST_CODE + "/.well-known/acme-challenge/" + challengeFile
// 调用读取文件的函数
content, err := utils.ReadFile(filePath)
if err != nil {
zlog.Error("Error reading file: %v", err.Error())
}
if content != "" {
resp.StatusCode = http.StatusOK
resp.Status = http.StatusText(http.StatusOK)
resp.Body = io.NopCloser(bytes.NewBuffer([]byte(content)))
resp.ContentLength = int64(len(content))
resp.Header.Set("Content-Length", strconv.FormatInt(int64(len(content)), 10))
// 调用读取文件的函数
content, err := utils.ReadFile(filePath)
if err != nil {
zlog.Error("Error reading file: %v", err.Error())
}
if content != "" {
resp.StatusCode = http.StatusOK
resp.Status = http.StatusText(http.StatusOK)
resp.Body = io.NopCloser(bytes.NewBuffer([]byte(content)))
resp.ContentLength = int64(len(content))
resp.Header.Set("Content-Length", strconv.FormatInt(int64(len(content)), 10))
weblogfrist.ACTION = "放行"
weblogfrist.STATUS = resp.Status
weblogfrist.STATUS_CODE = resp.StatusCode
weblogfrist.TASK_FLAG = 1
weblogfrist.BackendCheckCost = time.Now().UnixNano()/1e6 - backendCheckStart //响应数据处理时间
global.GQEQUE_LOG_DB.Enqueue(weblogfrist)
weblogfrist.ACTION = "放行"
weblogfrist.STATUS = resp.Status
weblogfrist.STATUS_CODE = resp.StatusCode
weblogfrist.TASK_FLAG = 1
weblogfrist.BackendCheckCost = time.Now().UnixNano()/1e6 - backendCheckStart //响应数据处理时间
global.GQEQUE_LOG_DB.Enqueue(weblogfrist)
}
}
} else if global.GCONFIG_RECORD_SSLHTTP_CHECK == 1 {
// 当配置为检查HTTP响应码且响应不是404/301/302时,记录警告信息
zlog.Warn(fmt.Sprintf("ACME Challenge检测:域名 %s 的 URL %s 返回了非预期的状态码 %d,影响证书验证,可在系统配置里面将sslhttp_check设置成0",
weblogfrist.HOST, weblogfrist.URL, resp.StatusCode))
}
} else {
//记录响应Header信息
+4
View File
@@ -85,6 +85,9 @@ func setConfigIntValue(name string, value int64, change int) {
case "fake_spider_captcha":
global.GCONFIG_RECORD_FAKE_SPIDER_CAPTCHA = value
break
case "sslhttp_check":
global.GCONFIG_RECORD_SSLHTTP_CHECK = value
break
default:
zlog.Warn("Unknown config item:", name)
}
@@ -210,6 +213,7 @@ func TaskLoadSetting(initLoad bool) {
updateConfigIntItem(initLoad, "ssl", "enable_http_80", global.GCONFIG_RECORD_ENABLE_HTTP_80, "启动80端口服务(为自动申请证书使用 HTTP文件验证类型需要,DNS验证不需要)", "int", "")
updateConfigIntItem(initLoad, "ssl", "sslorder_expire_day", global.GCONFIG_RECORD_SSLOrder_EXPIRE_DAY, "自动续期检测小于多少天开始发起自动申请 默认30天", "int", "")
updateConfigIntItem(initLoad, "ssl", "sslhttp_check", global.GCONFIG_RECORD_SSLHTTP_CHECK, "证书文件验证方式是否要严控后端.well-known 响应代码必须是404 301 302 ,默认1控制 0 不控制", "int", "")
updateConfigIntItem(initLoad, "network", "connect_time_out", global.GCONFIG_RECORD_CONNECT_TIME_OUT, "连接超时(默认30s", "int", "")
updateConfigIntItem(initLoad, "network", "keepalive_time_out", global.GCONFIG_RECORD_KEEPALIVE_TIME_OUT, "保持活动超时(默认30s", "int", "")