Suggested labels: security, enhancement
TL;DR (English)
You already did the urgent thing — PR #3 closes the XSS holes, which were the scary "another player runs code in your browser" bugs. 👏 This issue is the calmer, someday layer of security: two hardening steps that are totally fine to leave as-is while you're learning, but worth writing down so they're not forgotten if this ever goes public/serious.
Per CLAUDE.md, both of these are documented, intentional hobby tradeoffs — so this isn't "you did it wrong," it's "here's the graduation path." Two items:
Neither is urgent for a hobby game. Filing so it's on the map. 🗺️
中文详细说明
先说一句:紧急的那部分你已经搞定了 —— PR #3 把 XSS 堵上了,那才是"别人能在你浏览器里跑代码"的可怕 bug。👏 这个 issue 是更从容的、"以后再说"的安全加固。这两件事在你学习/玩耍阶段保持现状完全 OK,只是写下来,免得将来真要公开/正式上线时忘了。
CLAUDE.md 里写明了:这两条都是你有意做的、有记录的业余取舍。所以这不是"你做错了",而是"毕业路线图"。
(1) 把密码哈希,而不是明文存
现在密码是明文存和比对的:
server.js:362 —— if (!u || u.password !== password)(明文比对)
server.js:562 —— 注册时直接 password 存进 users.json
public/game.js:17542 —— 客户端把明文密码写进 localStorage
为什么要改: 万一 users.json 泄露(或有人翻到 localStorage),所有人的密码就直接暴露了 —— 而且很多人到处用同一个密码。哈希之后,存的是"加盐后的乱码",就算泄露也还原不出原密码。
怎么改(用 Node 自带的 crypto,不用装任何东西):
const crypto = require('crypto');
// 注册时:
function hashPassword(pw) {
const salt = crypto.randomBytes(16).toString('hex');
const hash = crypto.scryptSync(pw, salt, 64).toString('hex');
return `${salt}:${hash}`; // 存这个字符串,而不是明文
}
// 登录时:
function checkPassword(pw, stored) {
const [salt, hash] = stored.split(':');
const test = crypto.scryptSync(pw, salt, 64).toString('hex');
return crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(test));
}
💡 客户端那边,登录后别再存明文密码到 localStorage —— 存一个登录后服务器发的"令牌"(token)更安全。这步可以等哈希做完再说。
(2) /shop/inventory 别把密码放进网址
server.js:342-345:
app.get('/shop/inventory', (req, res) => {
const username = req.query.username;
const password = req.query.password; // ← 密码出现在 URL 里
为什么要改: 网址会被写进服务器日志、Cloudflare/代理日志、甚至浏览器历史记录。密码躺在网址里 = 到处留底。
怎么改: 把它从 app.get 改成 app.post,密码从 req.body 取(跟 /shop/buy 一模一样),客户端那边对应的请求也改成 POST + body。
🔗 相关 / Related: PR #3 已经把"XSS + 明文密码"这个危险组合里最危险的一半(XSS)干掉了。这个 issue 是把另一半也补上 —— 等将来真要上线,你就两头都稳了。不急,慢慢来。做得很棒!🔐
Suggested labels:
security,enhancementTL;DR (English)
You already did the urgent thing — PR #3 closes the XSS holes, which were the scary "another player runs code in your browser" bugs. 👏 This issue is the calmer, someday layer of security: two hardening steps that are totally fine to leave as-is while you're learning, but worth writing down so they're not forgotten if this ever goes public/serious.
Per
CLAUDE.md, both of these are documented, intentional hobby tradeoffs — so this isn't "you did it wrong," it's "here's the graduation path." Two items:server.js:362compare,server.js:562store) and saved tolocalStorageon the client (public/game.js:17542). Node has a built-in hasher (crypto.scrypt) — nonpm installneeded.GET /shop/inventoryreads?username=…&password=…from the query string (server.js:342-345). URLs get written to server logs, proxy logs, and browser history. Switch it toPOSTwith the password in the request body — exactly like/shop/buyalready does.Neither is urgent for a hobby game. Filing so it's on the map. 🗺️
中文详细说明
先说一句:紧急的那部分你已经搞定了 —— PR #3 把 XSS 堵上了,那才是"别人能在你浏览器里跑代码"的可怕 bug。👏 这个 issue 是更从容的、"以后再说"的安全加固。这两件事在你学习/玩耍阶段保持现状完全 OK,只是写下来,免得将来真要公开/正式上线时忘了。
CLAUDE.md里写明了:这两条都是你有意做的、有记录的业余取舍。所以这不是"你做错了",而是"毕业路线图"。(1) 把密码哈希,而不是明文存
现在密码是明文存和比对的:
server.js:362——if (!u || u.password !== password)(明文比对)server.js:562—— 注册时直接password存进users.jsonpublic/game.js:17542—— 客户端把明文密码写进localStorage为什么要改: 万一
users.json泄露(或有人翻到 localStorage),所有人的密码就直接暴露了 —— 而且很多人到处用同一个密码。哈希之后,存的是"加盐后的乱码",就算泄露也还原不出原密码。怎么改(用 Node 自带的
crypto,不用装任何东西):(2)
/shop/inventory别把密码放进网址server.js:342-345:为什么要改: 网址会被写进服务器日志、Cloudflare/代理日志、甚至浏览器历史记录。密码躺在网址里 = 到处留底。
怎么改: 把它从
app.get改成app.post,密码从req.body取(跟/shop/buy一模一样),客户端那边对应的请求也改成 POST + body。