From de0aadb37fd2db094feda9dea4e1e942cb1ce89e Mon Sep 17 00:00:00 2001 From: Bereket Engida Date: Sat, 12 Apr 2025 21:26:58 +0300 Subject: [PATCH] docs(security): add IP address header configuration for Better Auth --- docs/content/docs/reference/security.mdx | 20 +++++++++++ .../better-auth/src/utils/get-request-ip.ts | 36 +++++++++++-------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/docs/content/docs/reference/security.mdx b/docs/content/docs/reference/security.mdx index 076064f69f..339124847b 100644 --- a/docs/content/docs/reference/security.mdx +++ b/docs/content/docs/reference/security.mdx @@ -46,6 +46,26 @@ Plugins can also set custom cookie options to align with specific security needs Better Auth includes built-in rate limiting to safeguard against brute-force attacks. Rate limits are applied across all routes by default, with specific routes subject to stricter limits based on potential risk. +## IP Address Headers + +Better Auth uses client IP addresses for rate limiting and security monitoring. By default, it reads the IP address from the standard `X-Forwarded-For` header. However, you can configure a specific trusted header to ensure accurate IP address detection and prevent IP spoofing attacks. + +You can configure the IP address header in your Better Auth configuration: + +```typescript +{ + security: { + ipAddress: { + ipAddressHeaders: ['cf-connecting-ip'] // or any other custom header + } + } +} +``` + +This ensures that Better Auth only accepts IP addresses from your trusted proxy's header, making it more difficult for attackers to bypass rate limiting or other IP-based security measures by spoofing headers. + +> **Important**: When setting a custom IP address header, ensure that your proxy or load balancer is properly configured to set this header, and that it cannot be set by end users directly. + ## Trusted Origins Trusted origins prevent CSRF attacks and block open redirects. You can set a list of trusted origins in the `trustedOrigins` configuration option. Requests from origins not on this list are automatically blocked. diff --git a/packages/better-auth/src/utils/get-request-ip.ts b/packages/better-auth/src/utils/get-request-ip.ts index 2f41420b7f..547729b77c 100644 --- a/packages/better-auth/src/utils/get-request-ip.ts +++ b/packages/better-auth/src/utils/get-request-ip.ts @@ -12,25 +12,33 @@ export function getIp( if (isTest) { return testIP; } - const ipHeaders = options.advanced?.ipAddress?.ipAddressHeaders; - const keys = ipHeaders || [ - "x-client-ip", - "x-forwarded-for", - "cf-connecting-ip", - "fastly-client-ip", - "x-real-ip", - "x-cluster-client-ip", - "x-forwarded", - "forwarded-for", - "forwarded", - ]; + const headers = "headers" in req ? req.headers : req; - for (const key of keys) { + + const defaultHeaders = ["x-forwarded-for"]; + + const ipHeaders = + options.advanced?.ipAddress?.ipAddressHeaders || defaultHeaders; + + for (const key of ipHeaders) { const value = "get" in headers ? headers.get(key) : headers[key]; if (typeof value === "string") { const ip = value.split(",")[0].trim(); - if (ip) return ip; + if (isValidIP(ip)) { + return ip; + } } } return null; } + +function isValidIP(ip: string): boolean { + const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/; + if (ipv4Regex.test(ip)) { + const parts = ip.split(".").map(Number); + return parts.every((part) => part >= 0 && part <= 255); + } + + const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/; + return ipv6Regex.test(ip); +}