{"record":{"id":"1a3c3a20810af995","repo":"jeecgboot/JeecgBoot","slug":"sign","errorCode":null,"errorMessage":"Sign签名校验失败！","messagePattern":"Sign签名校验失败！","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/aspect/SignatureCheckAspect.java","lineNumber":103,"sourceCode":"        HttpServletRequest request = attributes.getRequest();\n        log.info(\"X-SIGN: {}, X-TIMESTAMP: {}\", request.getHeader(\"X-SIGN\"), request.getHeader(\"X-TIMESTAMP\"));\n        \n        try {\n            // 直接调用SignAuthInterceptor的验证逻辑\n            signAuthInterceptor.validateSignature(request, bodyParam);\n            log.info(\"AOP签名验证通过\");\n            \n        } catch (IllegalArgumentException e) {\n            // 使用注解中配置的错误消息，或者保留原始错误消息\n            String errorMessage = signatureCheck.errorMessage();\n            log.error(\"AOP签名验证失败: {}\", e.getMessage());\n            \n            if (\"Sign签名校验失败！\".equals(errorMessage)) {\n                // 如果是默认错误消息，使用原始的详细错误信息\n                throw e;\n            } else {\n                // 如果是自定义错误消息，使用自定义消息\n                throw new IllegalArgumentException(errorMessage, e);\n            }\n        } catch (Exception e) {\n            // 包装其他异常\n            String errorMessage = signatureCheck.errorMessage();\n            log.error(\"AOP签名验证异常: {}\", e.getMessage());\n            throw new IllegalArgumentException(errorMessage, e);\n        }\n    }\n}\n","sourceCodeStart":85,"sourceCodeEnd":113,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/aspect/SignatureCheckAspect.java#L85-L113","documentation":"Thrown by SignatureCheckAspect when signAuthInterceptor.validateSignature() throws an IllegalArgumentException during signature validation, and the @SignatureCheck annotation's errorMessage() is set to the default 'Sign签名校验失败！'. In this case the original detailed error (from SignAuthInterceptor) is re-thrown as-is. If a custom errorMessage is configured, a new IllegalArgumentException with that custom message is thrown instead. This means the X-SIGN header is missing, the timestamp is expired, or the signature does not match the computed value.","triggerScenarios":"API request to a @SignatureCheck-annotated endpoint without the X-SIGN header; X-SIGN value does not match the HMAC/signature computed from the request parameters; X-TIMESTAMP is missing or outside the allowed time window; request body was modified after signing; wrong signing key configured on client vs server.","commonSituations":"Client and server have different signing secret keys; client-side signature algorithm does not match server-side (SignAuthInterceptor); timestamp clock skew between client and server exceeds the allowed window; request body is modified by a proxy/gateway after signing; front-end omits the X-SIGN or X-TIMESTAMP header.","solutions":["Verify the signing secret key matches between client and server (jeecg.sign.secret configuration).","Ensure the client sends both X-SIGN (computed signature) and X-TIMESTAMP headers.","Check for clock skew — the server validates timestamp freshness; sync client and server clocks (NTP).","Verify the signature algorithm matches — review SignAuthInterceptor.validateSignature() for the exact signing logic (parameter sorting, body inclusion, hash algorithm).","Ensure no intermediary (gateway, proxy) modifies the request body or query parameters after signing."],"exampleFix":"// Front-end: compute and send signature\nconst params = { id: 123, name: 'test', _t: Date.now() };\nconst signStr = Object.keys(params).sort().map(k => `${k}=${params[k]}`).join('&');\nconst sign = CryptoJS.HmacSHA256(signStr, SIGN_SECRET).toString();\n\naxios.post('/api/signed-endpoint', body, {\n    headers: {\n        'X-SIGN': sign,\n        'X-TIMESTAMP': params._t.toString()\n    }\n});\n// Verify: server sign secret == client sign secret\n// Verify: parameter sorting and concatenation order match server logic","handlingStrategy":"validation","validationCode":"// Front-end: compute and verify signature before sending\nconst sortedParams = Object.keys(params).sort();\nconst signStr = sortedParams.map(k => `${k}=${params[k]}`).join('&');\nconst expectedSign = CryptoJS.HmacSHA256(signStr + timestamp, SIGN_SECRET).toString();\nif (expectedSign !== computedSign) {\n    console.error('Signature mismatch — do not send');\n}","typeGuard":null,"tryCatchPattern":"try {\n    // call signed API endpoint\n} catch (error) {\n    if (error.response?.data?.message?.includes('签名校验失败')) {\n        log.error('Signature validation failed — check signing key and algorithm');\n    }\n    throw error;\n}","preventionTips":["Ensure the signing secret matches exactly between client and server.","Sync clocks (NTP) — timestamp validation rejects skewed requests.","Review SignAuthInterceptor.validateSignature() for the exact signing algorithm (param sorting, body hashing).","Ensure no proxy/gateway modifies request body or params after signing.","Send both X-SIGN and X-TIMESTAMP headers on every signed request."],"tags":["signature","api-security","authentication","hmac","timestamp"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}