Skip to content

fix: resolve all six CodeQL security alerts - #44

Merged
houko merged 1 commit into
mainfrom
fix/codeql-security-alerts
Sep 9, 2026
Merged

fix: resolve all six CodeQL security alerts#44
houko merged 1 commit into
mainfrom
fix/codeql-security-alerts

Conversation

@houko

@houko houko commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Fixes all six CodeQL alerts. They are all in pre-existing code — CodeQL had never run on this repository until #43, so this is the first time anyone has seen them.

Alert Severity Location
TrustManager that accepts all certificates high core/.../HttpUtil.java
Unsafe hostname verification medium core/.../HttpUtil.java
Failure to use secure cookies medium core/.../HttpUtil.java
Uncontrolled data used in path expression high core/.../FileUtil.java
Insecure randomness ×2 high website/.../UserModel.java, AdminModel.java

TLS validation was switched off entirely

MyX509TrustManager had an empty checkServerTrusted and returned null from getAcceptedIssuers. TrustAnyHostnameVerifier.verify returned true unconditionally. Together they disable certificate-chain and hostname validation on every HTTPS request this utility makes — any machine on the path can decrypt and rewrite the traffic.

Both classes are removed, and initHttps no longer overrides SSLSocketFactory or HostnameVerifier. The JDK default validates properly.

This is a behaviour change. Any server this code talks to that presents a self-signed or expired certificate will now fail to connect. That is the bug becoming visible rather than a new bug: the fix is to add the certificate to the trust store, not to turn validation off.

Cookies lacked the secure flag

setCookie set httpOnly but not secure, so the cookie was sent over plaintext HTTP. Added setSecure(true) and SameSite=Lax. Worth knowing when testing locally: browsers will not return a secure cookie over plain HTTP.

Path injection in FileUtil

getNewFileName builds a filename from the email local-part and the file extension, both user-supplied. Taking "everything after the last dot" as the extension means an upload named a.b/../../evil contributes b/../../evil to the path. The result was concatenated straight into a FileOutputStream path.

Both components are now filtered to [A-Za-z0-9_-], and the write resolves through normalize() then startsWith(root) against a dedicated upload directory — the same canonical guard used in the fileupload module, which CodeQL recognises.

While in there: savePath was initialised to "" and never assigned a directory, so uploads landed in the process working directory. Now they go to upload/.

Insecure randomness

The two alerts point at @Data on UserModel and AdminModel, which is CodeQL following the taint into Lombok-generated setters. The actual source is RandomUtil: getTonken, randomPwd and createSalt all called RandomStringUtils.random(), which is backed by java.util.Random — a 48-bit seed and a published algorithm, so observing a handful of outputs is enough to predict the rest. These values are used as password salts and cache tokens, where predictability defeats the purpose.

Switched to RandomStringUtils.secure(), which is SecureRandom-backed (available since commons-lang3 3.16; this project is on 3.20).

RandomUtil.random(min, max), randomElement and isGenerate are left on ThreadLocalRandom. They pick demo data, not secrets, and CodeQL does not flag them.

Verification

New SecurityHardeningTest covers the parts that can be asserted directly — traversal fragments stripped from both filename components, secure and httpOnly both set on the cookie, salts of the right length with no collisions across 500 draws, and tokens that are all digits.

Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 -- info.xiaomo.core.utils.SecurityHardeningTest
[INFO] BUILD SUCCESS

Full build passes across all 21 modules with the existing 24 tests still green.

CodeQL 在本仓库首次完整扫描后报出 6 条告警(3 high / 2 medium / 1 high), 全部来自既有代码。逐条修复:

HttpUtil 的 TLS 校验(#11 high, #9 medium)
MyX509TrustManager 的 checkServerTrusted 是空实现、getAcceptedIssuers 返回 null, TrustAnyHostnameVerifier 的 verify 永远返回 true。两者合起来等于把 https 的安全性完全关掉, 任何中间人都能解密和篡改流量。现移除这两个类, 不再覆盖 SSLSocketFactory 与 HostnameVerifier, 交回 JDK 默认实现。

这是行为变更: 面向自签名或过期证书的服务端会开始连接失败。这正是应当暴露的问题, 正确做法是把证书加进信任库而不是关掉校验。

Cookie 缺少 secure(#10 medium)
setCookie 只设了 httpOnly。补上 secure(禁止明文链路发送)与 SameSite=Lax(缓解 CSRF)。注意本地用 http 调试时浏览器不会回传该 cookie。

FileUtil 路径注入(#8 high)
getNewFileName 用 email 前缀和文件扩展名拼文件名, 两段都来自用户输入。按"最后一个点之后"取扩展名时, a.b/../../evil 这样的文件名会把整段路径带进来。现在两段都只保留 [A-Za-z0-9_-], 落盘再用 normalize + startsWith 限制在 upload 目录内。

顺带修掉同一段代码里 savePath 为空串的问题 —— 原先文件是写进进程工作目录的。

不安全的随机数(#12, #13 high)
根源在 RandomUtil: getTonken / randomPwd / createSalt 都走 RandomStringUtils.random(), 底层是 java.util.Random, 种子只有 48 位且算法公开, 观察到少量输出即可推算后续全部结果。这些值被用作密码盐值和 token, 可预测等于形同虚设。改用 RandomStringUtils.secure()(SecureRandom 支撑)。

CodeQL 把告警报在 UserModel / AdminModel 的 @DaTa 上, 是因为 salt 经由 Lombok 生成的 setter 流入模型字段, 真正的源头在 RandomUtil。

新增 SecurityHardeningTest 覆盖文件名过滤、cookie 标志、盐值与 token 的取值质量。
@houko
houko merged commit 9c33104 into main Sep 9, 2026
4 checks passed
@houko
houko deleted the fix/codeql-security-alerts branch September 9, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant