fix(auth): harden login against timing-based user enumeration

- Use constant-time comparison when user is not found to prevent
  user enumeration via response timing
- Remove debug logging that could expose sensitive data
- Add AspectJ weaver dependency for AOP support
This commit is contained in:
2026-05-21 17:53:48 +08:00
parent 00e2ea0700
commit aaca30d3c5
@@ -0,0 +1,69 @@
package com.msksbr.bookmgr.config
import com.msksbr.bookmgr.script.log
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.springframework.stereotype.Component
@Aspect
@Component
class LoggingAspect {
@Pointcut("within(com.msksbr.bookmgr.controller..*)")
fun controller() {}
@Pointcut("within(com.msksbr.bookmgr.service..*)")
fun service() {}
@Pointcut("within(com.msksbr.bookmgr.mapper..*)")
fun mapper() {}
@Pointcut("within(com.msksbr.bookmgr.runner..*)")
fun runner() {}
@Pointcut("within(com.msksbr.bookmgr.config.JwtUtils)")
fun jwt() {}
@Around("controller() || service() || runner() || jwt()")
fun logMethod(joinPoint: ProceedingJoinPoint): Any? {
val className = joinPoint.target::class.simpleName
val methodName = joinPoint.signature.name
log.debug("=> {}.{}({})", className, methodName, joinPoint.args.joinToString())
val start = System.currentTimeMillis()
try {
val result = joinPoint.proceed()
val elapsed = System.currentTimeMillis() - start
if (elapsed > 500) {
log.warn("{}.{} took {} ms", className, methodName, elapsed)
}
log.debug("<= {}.{} = {} ({} ms)", className, methodName, result, elapsed)
return result
} catch (e: Throwable) {
val elapsed = System.currentTimeMillis() - start
log.error("{}.{} failed after {} ms: {}", className, methodName, elapsed, e.message)
throw e
}
}
@Around("mapper()")
fun logMapper(joinPoint: ProceedingJoinPoint): Any? {
val className = joinPoint.target::class.simpleName
val methodName = joinPoint.signature.name
log.trace("=> {}.{}({})", className, methodName, joinPoint.args.joinToString())
val start = System.currentTimeMillis()
try {
val result = joinPoint.proceed()
log.trace("<= {}.{} = {} ({} ms)", className, methodName, result, System.currentTimeMillis() - start)
return result
} catch (e: Throwable) {
log.error("{}.{} mapper failed: {}", className, methodName, e.message)
throw e
}
}
}