Golang中密码错误返回的两种情况原因分析
Golang中密码错误返回的两种情况原因分析 为什么无论用户输入错误密码还是正确密码,都会返回错误?
另外,如何向用户显示他们的邮箱也是错误的?
func Login(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var user model.User
var dbUser model.User
if err := json.NewDecoder(r.Body).Decode(&user); err == nil {
if _, err := service.Login_User(&user); err == nil {
json.NewEncoder(w).Encode(user)
} else {
w.WriteHeader(http.StatusInternalServerError)
//w.Write([]byte)
json.NewEncoder(w).Encode(err)
}
} else {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
userPass := []byte(user.Password)
dbPass := []byte(dbUser.Password)
PassErr := bcrypt.CompareHashAndPassword(dbPass, userPass)
if PassErr != nil {
w.Write([]byte(`{"response":"Wrong Password"}`))
return
}
}
更多关于Golang中密码错误返回的两种情况原因分析的实战教程也可以访问 https://www.itying.com/category-94-b0.html
3 回复
我也遇到了同样的错误,对此有什么建议吗?请回复。先谢谢了。
更多关于Golang中密码错误返回的两种情况原因分析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好,@Rajrup_Das,
这个函数似乎没有在任何地方填充 dbUser。
关于电子邮件,我猜 model.User 中有一个字段,你需要通过检查电子邮件字符串是否包含“@”并且不包含电子邮件地址中非法的字符来验证它。应该有一些可用的包来处理这个。(搜索 pkg.go.dev,我相信你会找到不止一个。)
你的代码存在几个关键问题,导致无论密码是否正确都返回错误:
主要问题分析:
1. 逻辑顺序错误
密码验证代码被放在了错误处理块之后,导致永远不会执行。
2. 数据库查询缺失
dbUser 变量从未从数据库获取数据,始终为空。
3. 错误处理逻辑混乱
service.Login_User(&user) 成功后直接返回,但后续还有密码验证代码。
修正后的代码:
func Login(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var loginRequest struct {
Email string `json:"email"`
Password string `json:"password"`
}
// 解析请求体
if err := json.NewDecoder(r.Body).Decode(&loginRequest); err != nil {
http.Error(w, "Invalid request format", http.StatusBadRequest)
return
}
// 1. 先验证邮箱是否存在
dbUser, err := service.GetUserByEmail(loginRequest.Email)
if err != nil {
// 邮箱不存在的情况
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{
"error": "Invalid email or password", // 不明确提示邮箱错误
})
return
}
// 2. 验证密码
userPass := []byte(loginRequest.Password)
dbPass := []byte(dbUser.Password)
if err := bcrypt.CompareHashAndPassword(dbPass, userPass); err != nil {
// 密码错误的情况
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{
"error": "Invalid email or password", // 保持相同错误信息
})
return
}
// 3. 登录成功
json.NewEncoder(w).Encode(map[string]interface{}{
"message": "Login successful",
"user": dbUser,
})
}
安全建议的实现:
如果需要区分错误类型但保持安全,可以这样处理:
func Login(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var loginRequest struct {
Email string `json:"email"`
Password string `json:"password"`
}
if err := json.NewDecoder(r.Body).Decode(&loginRequest); err != nil {
http.Error(w, "Invalid request format", http.StatusBadRequest)
return
}
// 验证邮箱格式
if !isValidEmail(loginRequest.Email) {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"error": "Invalid email format",
})
return
}
// 检查用户是否存在
userExists, err := service.CheckUserExists(loginRequest.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
if !userExists {
// 模拟密码验证耗时,防止邮箱枚举攻击
bcrypt.CompareHashAndPassword(
[]byte("$2a$10$fakehashforsecurity"),
[]byte(loginRequest.Password),
)
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{
"error": "Invalid credentials",
})
return
}
// 获取用户并验证密码
dbUser, err := service.GetUserByEmail(loginRequest.Email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
if err := bcrypt.CompareHashAndPassword(
[]byte(dbUser.Password),
[]byte(loginRequest.Password),
); err != nil {
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{
"error": "Invalid credentials",
})
return
}
// 登录成功
json.NewEncoder(w).Encode(map[string]interface{}{
"message": "Login successful",
"user": sanitizeUserData(dbUser),
})
}
// 辅助函数:清理用户敏感数据
func sanitizeUserData(user model.User) map[string]interface{} {
return map[string]interface{}{
"id": user.ID,
"email": user.Email,
"name": user.Name,
}
}
// 辅助函数:验证邮箱格式
func isValidEmail(email string) bool {
return strings.Contains(email, "@") && strings.Contains(email, ".")
}
关键改进点:
- 统一错误信息:始终返回"Invalid credentials",防止攻击者枚举有效邮箱
- 时序一致性:邮箱不存在时也进行密码验证,保持响应时间一致
- 逻辑清晰:按顺序验证邮箱格式→邮箱存在→密码正确
- 数据清理:返回用户数据时移除密码等敏感信息
这样的实现既保证了安全性,又修复了原代码中的逻辑错误。

