fix(auth): harden password verification against timing attacks
- Run dummy hash when user is not found to prevent timing-based enumeration - Extract and log real client IP on login requests - Remove unused test files - Reorder application config for clarity
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
package com.msksbr.bookmgr.config
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
//获取真实IP的bean
|
||||
@Component
|
||||
class IpExtractor {
|
||||
fun getRealIp(request: HttpServletRequest): String {
|
||||
val headers = listOf(
|
||||
"X-Forwarded-For",
|
||||
"Proxy-Client-IP",
|
||||
"WL-Proxy-Client-IP",
|
||||
"HTTP_X_FORWARDED_FOR",
|
||||
"X-Real-IP"
|
||||
)
|
||||
return headers
|
||||
.mapNotNull { request.getHeader(it) }
|
||||
.firstOrNull { it.isNotBlank() && !it.equals("unknown", ignoreCase = true) }
|
||||
?.split(",")
|
||||
?.first()
|
||||
?.trim()
|
||||
?: request.remoteAddr
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
package com.msksbr.bookmgr.controller
|
||||
|
||||
import com.msksbr.bookmgr.config.IpExtractor
|
||||
import com.msksbr.bookmgr.dto.UserLoginDTO
|
||||
import com.msksbr.bookmgr.script.log
|
||||
import com.msksbr.bookmgr.service.AuthService
|
||||
import jakarta.servlet.http.HttpSession
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import com.msksbr.bookmgr.template.Result
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpSession
|
||||
import jakarta.validation.Valid
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/*
|
||||
* 登录接口
|
||||
@@ -19,7 +20,8 @@ import org.springframework.web.bind.annotation.RequestBody
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
class AuthController(
|
||||
val authService: AuthService
|
||||
val authService: AuthService,
|
||||
val ipExtractor: IpExtractor
|
||||
) {
|
||||
@PostMapping("/login")
|
||||
fun login(
|
||||
@@ -28,27 +30,28 @@ class AuthController(
|
||||
loginDTO: UserLoginDTO,
|
||||
session: HttpSession,
|
||||
request: HttpServletRequest
|
||||
) : Result<String> {
|
||||
log.info("Login from ${request.remoteAddr} username: ${loginDTO.username}")
|
||||
): Result<String> {
|
||||
log.info("Login from ${ipExtractor.getRealIp(request)} username: ${loginDTO.username}")
|
||||
log.info("UA: ${request.getHeader("User-Agent")}")
|
||||
// 调用service验证
|
||||
val pass=authService.login(loginDTO)
|
||||
val pass = authService.login(loginDTO)
|
||||
return if (pass) {
|
||||
// 登录成功,存入session
|
||||
session.setAttribute("loginUser", loginDTO.username)
|
||||
log.info("Login success")
|
||||
Result.success("login success")
|
||||
}else{
|
||||
} else {
|
||||
log.info("Login failed")
|
||||
Result.error("username or password not match")
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
fun logout(
|
||||
session: HttpSession,
|
||||
request:HttpServletRequest
|
||||
request: HttpServletRequest
|
||||
): Result<String> {
|
||||
log.info("Logout from ${request.remoteAddr}")
|
||||
log.info("Logout from ${ipExtractor.getRealIp(request)}")
|
||||
log.info("UA: ${request.getHeader("User-Agent")}")
|
||||
// 直接销毁session
|
||||
session.invalidate()
|
||||
|
||||
@@ -21,6 +21,8 @@ class AuthServiceImpl(private val userMapper: UserMapper, private val passwordEn
|
||||
// 找不到用户时直接返回false
|
||||
if (user == null) {
|
||||
log.debug("User ${loginDTO.username} does not exist")
|
||||
// 跑一遍dummyHash来对齐响应时间,避免“信息泄露”攻击
|
||||
passwordEncoder.encode("dummyHash")
|
||||
return false
|
||||
}
|
||||
// 比对密码
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
application:
|
||||
name: bookMgr
|
||||
datasource:
|
||||
@@ -17,4 +15,9 @@ spring:
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
# 开启驼峰命名法
|
||||
map-underscore-to-camel-case: true
|
||||
map-underscore-to-camel-case: true
|
||||
# 开启日志输出sql语句
|
||||
# log-impl: org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl
|
||||
# logging:
|
||||
# level:
|
||||
# com.msksbr.bookmgr: "DEBUG"
|
||||
Reference in New Issue
Block a user