

新闻资讯
技术学院密码校验须用 bcrypt.CompareHashAndPassword 比对哈希值,禁用明文比较;登录接口需统一错误提示、限流防爆破、禁打明文密码日志;Session/JWT 要绑定 IP、UA、过期时间并安全签名;数据库操作必须参数化查询且处理 sql.ErrNoRows。
Go 里最常见错误是把前端传来的 password 和数据库存的明文(或简单 base64)直接用 == 比较。这既不安全,也不符合实际存储方式。真实场景中,密码必须经哈希(如 bcrypt)处理后存储,校验时要用专用比对函数。
user.Password == input.Password 这类逻辑golang.org/x/crypto/bcrypt 的 bcrypt.CompareHashAndPassword,它自带时序攻击防护bcrypt 哈希值(形如 $2a$10$...),就直接传进去比;别自己解码或截断CompareHashAndPassword 第一个参数是哈希值([]byte),第二个是原始密码([]byte),顺序反了会始终返回错误一个裸奔的 POST /login 接口,只要返回 {"error": "wrong password"} 就等于告诉攻击者“用户名存在”。更糟的是,没限流时,脚本可每秒试几百次。
{"error": "invalid credentials"},不区分“用户不存在”和“密码错误”username 做请求频控,可用 golang.org/x/time/rate 或简单内存计数(上线前换 Redis)log.Printf("login failed for user %s", username)
只生成一个随机字符串当 session ID 或 JWT,却不绑定 IP、User-Agent、过期时间,等于给攻击者留后门。
gorilla/sessions),设置 Options.HttpOnly = true、Options.Secure = true(HTTPS 环境下)sub(用户 ID)、exp(短时效,如 30m)、ip(客户端真实 IP)、ua_hash(sha256(UserAgent) 前 16 字节)SigningKey)绝不能硬编码在代码里,从环境变量或 secret manager 加载jti 并检查是否被撤销用 database/sql 查用户时,拼接 "SELECT * FROM users WHERE username = '" + username + "'" 是高危操作;而查不到用户就直接取 rows[0] 会 panic。
db.QueryRow("SELECT id, password_hash FROM users WHERE username = ?", u
sername)
err := row.Scan(&id, &hash) 后,必须检查 err == sql.ErrNoRows,而不是忽略或直接 if err != nil 就返回 500pwd_hash,代码里就该用 pwd_hash,别想当然写成 password
username 做基础过滤:拒绝空格、控制字符、长度超 64 的输入,避免后续环节异常func loginHandler(w http.ResponseWriter, r *http.Request) {
var user struct {
ID int64 `json:"id"`
PasswordHash []byte `json:"-"` // 不暴露
}
err := db.QueryRow("SELECT id, password_hash FROM users WHERE username = ?", r.FormValue("username")).Scan(&user.ID, &user.PasswordHash)
if err == sql.ErrNoRows {
http.Error(w, `{"error": "invalid credentials"}`, http.StatusUnauthorized)
return
}
if err != nil {
http.Error(w, `{"error": "server error"}`, http.StatusInternalServerError)
return
}
if err = bcrypt.CompareHashAndPassword(user.PasswordHash, []byte(r.FormValue("password"))); err != nil {
http.Error(w, `{"error": "invalid credentials"}`, http.StatusUnauthorized)
return
}
// 此处签发 token 或写 session...
}真正难的不是写完登录,而是让每个分支都处理到边界情况:查无此人、哈希格式错、token 签发失败、客户端没带 Cookie、IP 被临时封禁……这些地方漏一个,就可能变成线上事故。