fix: always sign cch=00000 placeholder and normalize env fingerprints

Two bugs identified from article "Claude Code封号真相":

1. cch=00000 never replaced (fix):
   signBillingHeaderCCH was gated by enableCCH (default false), so the
   cch=00000 placeholder injected by buildBillingAttributionBlockJSON was
   sent to Anthropic as-is — an obvious fake signal. The function already
   guards itself via regex match, so the enableCCH gate is removed.

2. NormalizeSystemPromptEnv was dead code (fix):
   Platform/Shell/OS Version/Working directory fields in user system prompts
   leaked real machine info (e.g. "Darwin 25.3.0", "/Users/win/...") that
   Anthropic could use to correlate requests across accounts. Now normalized
   to canonical values before injecting into the messages pair.
This commit is contained in:
win 2026-05-02 17:07:07 +08:00
parent c5eb305f7f
commit 038f0ee8d3

View File

@ -4124,10 +4124,12 @@ func rewriteSystemForNonClaudeCode(body []byte, system any) []byte {
// 模型仍通过 messages 接收完整指令,保留客户端功能
ccPromptTrimmed := strings.TrimSpace(claudeCodeSystemPrompt)
if originalSystemText != "" && originalSystemText != ccPromptTrimmed && !hasClaudeCodePrefix(originalSystemText) {
// 规范化 env 字段Platform/Shell/OS/路径),防止真实机器信息被 Anthropic 用作跨账号关联信号。
normalizedSystemText := NormalizeSystemPromptEnv(originalSystemText)
instrMsg, err1 := json.Marshal(map[string]any{
"role": "user",
"content": []map[string]any{
{"type": "text", "text": "[System Instructions]\n" + originalSystemText},
{"type": "text", "text": "[System Instructions]\n" + normalizedSystemText},
},
})
ackMsg, err2 := json.Marshal(map[string]any{
@ -6064,9 +6066,9 @@ func (s *GatewayService) buildUpstreamRequest(ctx context.Context, c *gin.Contex
// OAuth账号应用统一指纹和metadata重写受设置开关控制
var fingerprint *Fingerprint
enableFP, enableMPT, enableCCH := true, false, false
enableFP, enableMPT, _ := true, false, false
if s.settingService != nil {
enableFP, enableMPT, enableCCH = s.settingService.GetGatewayForwardingSettings(ctx)
enableFP, enableMPT, _ = s.settingService.GetGatewayForwardingSettings(ctx)
}
if account.IsOAuth() && s.identityService != nil {
// 1. 获取或创建指纹包含随机生成的ClientID
@ -6097,10 +6099,9 @@ func (s *GatewayService) buildUpstreamRequest(ctx context.Context, c *gin.Contex
if fingerprint != nil {
body = syncBillingHeaderVersion(body, fingerprint.UserAgent)
}
// CCH 签名:将 cch=00000 占位符替换为 xxHash64 签名(需在所有 body 修改之后)
if enableCCH {
body = signBillingHeaderCCH(body)
}
// CCH 签名:将 cch=00000 占位符替换为 xxHash64 签名(需在所有 body 修改之后)。
// 无占位符时函数为 no-op故无需 enableCCH gate — 占位符存在即意味着必须签名。
body = signBillingHeaderCCH(body)
req, err := http.NewRequestWithContext(ctx, "POST", targetURL, bytes.NewReader(body))
if err != nil {
@ -9278,9 +9279,9 @@ func (s *GatewayService) buildCountTokensRequest(ctx context.Context, c *gin.Con
// OAuth 账号:应用统一指纹和重写 userID受设置开关控制
// 如果启用了会话ID伪装会在重写后替换 session 部分为固定值
ctEnableFP, ctEnableMPT, ctEnableCCH := true, false, false
ctEnableFP, ctEnableMPT, _ := true, false, false
if s.settingService != nil {
ctEnableFP, ctEnableMPT, ctEnableCCH = s.settingService.GetGatewayForwardingSettings(ctx)
ctEnableFP, ctEnableMPT, _ = s.settingService.GetGatewayForwardingSettings(ctx)
}
var ctFingerprint *Fingerprint
if account.IsOAuth() && s.identityService != nil {
@ -9302,9 +9303,8 @@ func (s *GatewayService) buildCountTokensRequest(ctx context.Context, c *gin.Con
if ctFingerprint != nil && ctEnableFP {
body = syncBillingHeaderVersion(body, ctFingerprint.UserAgent)
}
if ctEnableCCH {
body = signBillingHeaderCCH(body)
}
// 无占位符时函数为 no-op故无需 ctEnableCCH gate。
body = signBillingHeaderCCH(body)
req, err := http.NewRequestWithContext(ctx, "POST", targetURL, bytes.NewReader(body))
if err != nil {