# 安全 (/docs/reference/security)

Better Auth 安全功能。



本页面包含有关 Better Auth 安全功能的信息。

## 密码哈希 [#密码哈希]

Better Auth 默认使用 `scrypt` 算法进行密码哈希。该算法设计为内存硬且 CPU 密集型，能够抵抗暴力破解攻击。您可以通过配置中的 `password` 选项自定义密码哈希函数。该选项应包含用于哈希密码的 `hash` 函数和用于验证密码的 `verify` 函数。

## 秘钥轮换 [#秘钥轮换]

Better Auth 支持在相同加密格式和用途内无破坏性地轮换 `BETTER_AUTH_SECRET`。通过 `secrets` 选项或 `BETTER_AUTH_SECRETS` 环境变量配置版本化密钥后，所有新加密的数据都会包含密钥版本标识符。解密时会根据版本直接查找密钥，无需尝试性解密。

在相同加密用途内，轮换前使用旧密钥加密的遗留数据（裸十六进制格式）仍可通过原始 `BETTER_AUTH_SECRET` 作为回退解密。常规密钥轮换无需数据库迁移或停机。数据下次写入时会惰性地使用当前密钥重新加密。

从共享加密密钥升级到用途专属密钥会改变待处理 OAuth 和 SAML state cookie 以及 OAuth Proxy 载荷使用的格式。保留原始密钥无法继续这些待处理流程。请一起升级参与的服务器，并重新启动切换前开始的登录和账户关联流程。请参阅 [state cookie 升级说明](/docs/reference/options#storestatestrategy)和 [OAuth Proxy 升级指南](/docs/plugins/oauth-proxy#upgrading-existing-deployments)。

配置细节请参见 [`secrets` 选项](/docs/reference/options#secrets)。

## 会话管理 [#会话管理]

### 会话过期 [#会话过期]

Better Auth 使用安全的会话管理来保护用户数据。会话存储在数据库或次级存储（如果配置了）中，以防止未经授权的访问。默认情况下，会话在 7 天后过期，您可以在配置中自定义这个值。此外，每次使用会话时，如果达到 `updateAge` 阈值（默认 1 天），过期时间将被延长。

### 会话撤销 [#会话撤销]

Better Auth 允许您撤销会话以增强安全性。当会话被撤销后，用户会退出登录，无法再访问应用。已登录用户还可以撤销自己的会话，以便从不同设备或浏览器登出。

更多详情请参见 [会话管理](/docs/concepts/session-management)。

## CSRF 保护 [#csrf-保护]

Better Auth 包含多重防护措施以防止跨站请求伪造（CSRF）攻击：

1. **避免简单请求**
   更多详情请参见 [避免简单请求](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/CSRF#avoiding_simple_requests)。默认情况下，Better Auth 更倾向于对会改变状态的操作使用非简单请求，通常通过要求一个非简单头部或 `Content-Type` 头部为 `application/json` 来实现。

   某些路由会有意接受 `application/x-www-form-urlencoded` 请求，以支持渐进增强或协议互操作性，包括登录/注册邮件流程以及某些回调/令牌样式的端点。这些路由依赖额外的保护措施，例如来源验证、适用时的 Fetch Metadata 检查，以及协议特定的状态或 nonce 验证。

2. **来源验证**
   每个请求的 `Origin` 头部都会被验证，以确认它来自您的应用或其他明确受信任的来源。来自不可信来源的请求会被拒绝。默认情况下，Better Auth 信任您应用的基础 URL，但您可以通过 `trustedOrigins` 配置选项指定其他受信任的来源。

   使用 `Referrer-Policy: no-referrer` 的页面发起的同源表单提交可能携带 `Origin: null`。当 `Sec-Fetch-Site` 确认请求为同源时，Better Auth 会改为根据 `trustedOrigins` 验证请求 URL 的来源。缺少此类 Fetch Metadata 证据的请求，以及目标为不受信任来源的请求，仍会被拒绝。

3. **安全 Cookie 设置**
   会话 Cookie 默认使用 `SameSite=Lax` 属性，防止浏览器在大多数跨站请求中发送 Cookie。您可以使用 `defaultCookieAttributes` 选项覆盖此行为。

4. **首次登录的 Fetch Metadata 防护**
   Better Auth 还使用 [Fetch Metadata 头部](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/CSRF#fetch_metadata)（`Sec-Fetch-Site`、`Sec-Fetch-Mode`、`Sec-Fetch-Dest`）为 **首次登录场景** 提供额外的 CSRF 防护，此时客户端尚未拥有任何 Cookie。

   此防护适用于 **登录和注册邮件路由**，这些路由接受表单提交（简单请求）以支持渐进增强模式。

   当收到 **没有 Cookie** 的登录或注册请求时：

   * 如果浏览器指示 **跨站导航**（例如：`Sec-Fetch-Site: cross-site` 且 `Sec-Fetch-Mode: navigate`），Better Auth **会阻止**该请求，将其视为潜在的登录 CSRF 攻击。

   * 如果请求携带 `Origin` 或 `Referer` 头部，Better Auth 会根据您的 `trustedOrigins` 配置验证它们，并拒绝不受信任的来源。无论客户端是否发送 Fetch Metadata 头部，此规则都适用。

   * 只有当请求 **既** 不携带 Fetch Metadata 头部 **也** 不携带 `Origin`/`Referer` 头部时（这在非浏览器客户端中很常见），Better Auth 才会回退到宽松行为，因此服务器到服务器和原生客户端不会被拒绝。

   此机制允许现代浏览器在 **不依赖 CSRF 令牌或客户端端 JavaScript** 的情况下，获得针对首次登录 CSRF 攻击的更强防护，并与渐进增强模式无缝协作。

   <Callout type="info">
     非浏览器 HTTP 客户端（移动应用、服务器到服务器）如果发送 `Origin` 或 `Referer` 头部，则必须使用 `trustedOrigins` 中列出的值，因为 Better Auth 在该头部存在时会对其进行验证。不发送来源头部且不发送 Fetch Metadata 的客户端（通常是非浏览器工具）不受影响。
   </Callout>

5. **GET 请求不执行变更（附带额外防护）**
   `GET` 请求被视为只读操作，不应更改应用状态。在必须执行变更的情况下——例如 OAuth 回调——Better Auth 会应用额外的安全措施，包括验证 `nonce` 和 `state` 参数以确保请求的真实性。

### 禁用安全检查 [#禁用安全检查]

Better Auth 提供了两个独立选项，用于禁用不同方面的安全检查：

#### `disableCSRFCheck` [#disablecsrfcheck]

禁用 **所有 CSRF 保护**，包括：

* 存在 Cookie 时的来源头部验证
* Fetch Metadata 检查（`Sec-Fetch-Site`、`Sec-Fetch-Mode`、`Sec-Fetch-Dest`）
* 首次登录场景的跨站导航阻止

```typescript
{
  advanced: {
    disableCSRFCheck: true
  }
}
```

<Callout type="warning">
  禁用 CSRF 检查将允许任意来源的请求携带 Cookie 并以用户身份执行操作，这会使您的应用暴露于 CSRF 攻击风险。
</Callout>

#### `disableOriginCheck` [#disableorigincheck]

禁用对 `trustedOrigins` 的 **URL 验证**，包括：

* `callbackURL` 验证
* `redirectTo` 验证
* `errorCallbackURL` 验证
* `newUserCallbackURL` 验证

```typescript
{
  advanced: {
    disableOriginCheck: true
  }
}
```

<Callout type="warning">
  禁用来源检查将允许任意 URL 用于重定向和回调，这会使您的应用暴露于开放重定向漏洞。
</Callout>

<Callout type="info">
  为保持向后兼容，设置 `disableOriginCheck: true` 也会禁用 CSRF 保护。如果您只想禁用 URL 验证而不影响 CSRF 保护，目前尚不可行——启用此选项时，两者会被一起禁用。
</Callout>

#### 总结 [#总结]

| 选项                   | 禁用的内容                               |
| -------------------- | ----------------------------------- |
| `disableCSRFCheck`   | 仅 CSRF 保护（来源头部验证、Fetch Metadata 检查） |
| `disableOriginCheck` | URL 验证以及 CSRF 保护（向后兼容）              |

## OAuth 状态与 PKCE [#oauth-状态与-pkce]

为了保护 OAuth 流程，Better Auth 使用配置的状态存储策略来存储 OAuth state 和 PKCE（Proof Key for Code Exchange）。默认情况下，state 载荷会存储在验证存储中，同时 state 值也会以签名 Cookie 的形式持久化以供验证。当 `storeStateStrategy` 设置为 `cookie` 时，完整的 state 载荷会被加密到一个短期 Cookie 中，而不是创建验证记录。

state 有助于防止 CSRF 攻击，而 PKCE 则可防御代码注入威胁。OAuth 回调处理完成后，Better Auth 会使相关 Cookie 过期，并在使用验证存储时删除已存储的验证记录。

## Cookies [#cookies]

当基础 URL 使用 `https` 时，Better Auth 默认分配安全的 Cookie。这些安全 Cookie 是加密的，仅通过安全连接传输，增加了额外的保护层。它们也默认设置 `sameSite` 属性为 `lax`，以防止跨站请求伪造攻击。同时启用了 `httpOnly` 属性，防止客户端 JavaScript 访问 Cookie。

对于跨子域 Cookie，您可以在配置中设置 `crossSubDomainCookies` 选项。该选项允许跨子域共享 Cookie，实现不同子域间的无缝认证。

### 自定义 Cookies [#自定义-cookies]

您可以自定义 Cookie 名称，以降低指纹识别攻击风险，并根据需要设置具体的 Cookie 选项以获得更细粒度的控制。详情请参见 [Cookie 选项](/docs/concepts/cookies)。

插件也可以设置自定义 Cookie 选项，以满足特定安全需求。如果在非浏览器环境中使用 Better Auth，插件还提供了安全管理 Cookie 的方法。

## 速率限制 [#速率限制]

Better Auth 内置了速率限制功能，用于防御暴力破解攻击。速率限制默认应用于所有路由，对潜在风险较高的特定路由会实施更严格的限制。

## IP 地址头部 [#ip-地址头部]

Better Auth 使用客户端 IP 地址进行速率限制和安全监控。默认情况下，它从标准的 `X-Forwarded-For` 头部读取 IP 地址。但您可以配置特定的受信任头部，以确保准确的 IP 地址检测并防止 IP 欺骗攻击。

您可以在 Better Auth 配置中设置 IP 地址头部：

```typescript
{
  advanced: {
    ipAddress: {
      ipAddressHeaders: ['cf-connecting-ip'] // 或其他自定义头部
    }
  }
}
```

这确保 Better Auth 仅接受来自您可信代理头部中的 IP 地址，使攻击者更难通过伪造头部绕过速率限制或其他基于 IP 的安全措施。

在代理链后面时，请在 `trustedProxies` 中列出您的代理，以便 Better Auth
解析真实客户端，而不是可被伪造的最左侧 `X-Forwarded-For`
令牌：

```typescript
{
  advanced: {
    ipAddress: {
      // 您的代理地址，而不是也涵盖客户端的宽泛私有地址范围
      trustedProxies: ['192.0.2.10', '10.0.0.0/24']
    }
  }
}
```

<Callout type="info">
  **重要**

  * 设置自定义 IP 地址头部时，请确保您的代理或负载均衡器已正确配置以设置此头部，并且它不能被终端用户直接设置。
  * 在开发/测试环境中，如果无法从头部获取 IP 地址，则会使用 `127.0.0.1` 作为回退。
</Callout>

## 受信任代理头部 [#受信任代理头部]

如果您的应用运行在反向代理或负载均衡器之后，Better Auth 可以从入站请求的 `X-Forwarded-Host` 和 `X-Forwarded-Proto` 头部推断基础 URL。这在应用可通过多个域名（例如 `example.com` 和 `app.example.dev`）访问，且您不想在配置中硬编码单一 `baseURL` 时非常实用。

启用 `trustedProxyHeaders` 且配置中（或环境变量中）未设置 `baseURL` 时，Better Auth 会在每个请求中使用转发头构建基础 URL。这意味着 OAuth 回调、邮件验证链接和重定向会自动使用用户加载应用时的域名。

```typescript
{
  advanced: {
    trustedProxyHeaders: true
  }
}
```

<Callout type="warning">
  仅当您信任到达应用程序的代理头部时才启用此选项。您的反向代理或负载均衡器必须正确配置以设置 `X-Forwarded-Host` 和 `X-Forwarded-Proto` 头部，且终端用户不得能够直接设置这些头部。如果不可信客户端伪造这些头部，他们可能会操纵重定向和回调 URL。
</Callout>

启用后，基础 URL 解析优先级如下：

1. 配置中的静态 `baseURL`（如果设置，代理头会被忽略）
2. 环境变量（`BETTER_AUTH_URL`、`NEXT_PUBLIC_BETTER_AUTH_URL` 等）
3. 当 `trustedProxyHeaders` 为 `true` 时，使用 `X-Forwarded-Host` + `X-Forwarded-Proto` 头部
4. 请求 URL 源作为最终回退

如果您正在从多个可接受的域名提供应用，通常应：

* **省略配置中的 `baseURL`**，使其基于代理头按请求动态推断
* 设置 &#x2A;*`trustedOrigins`** 为允许域名白名单（见下文）
* 保持 `crossSubDomainCookies` 已禁用——Cookie 默认仅限主机，每个域拥有独立会话

- **省略配置中的 `baseURL`**，使其基于代理头按请求动态推断
- 将 &#x2A;*`trustedOrigins`** 设为您批准域名的白名单（见下文）
- 保持 `crossSubDomainCookies` 未启用——默认 Cookie 仅限于主机，每个域拥有独立会话。

## 受信任来源 [#受信任来源]

相对回调和重定向 URL 支持标准路径、查询和片段语法，但必须以单个 `/` 开头。Better Auth 会拒绝协议相对 URL（`//...`）、反斜杠、控制字符以及路径中的编码路径分隔符。

### 基本用法 [#基本用法]

### 基本用法 [#基本用法-1]

最基本的用法是指定精确的来源，下面是一个可信来源配置的示例：

```typescript
{
  trustedOrigins: [
    "https://example.com",
    "https://app.example.com",
    "http://localhost:3000"
  ]
}
```

<Callout type="warning">
  不要在生产环境的认证实例的受信任来源列表中保留 localhost 来源。
</Callout>

### 通配符来源 [#通配符来源]

Better Auth 支持受信任来源中的通配符模式，允许通过单条规则信任多个子域：

```typescript
{
  trustedOrigins: [
    "*.example.com",             // 信任 example.com 的所有子域（任意协议）
    "https://*.example.com",     // 仅信任 example.com 的 HTTPS 子域
    "http://*.dev.example.com"   // 信任 dev.example.com 的所有 HTTP 子域
  ]
}
```

#### 特定协议通配符 [#特定协议通配符]

当使用带协议前缀（如 `https://`）的通配符模式时：

* 协议必须完全匹配
* 域名中的 `*` 可以替换为任意子域
* 使用不同协议的请求将被拒绝，即使域名匹配

#### 协议无关通配符 [#协议无关通配符]

当使用不带协议前缀的通配符模式（如 `*.example.com`）时：

* 任何协议（http、https 等）都会被接受
* 域名必须匹配通配符模式

### 自定义协议 [#自定义协议]

受信任来源还支持移动应用和浏览器扩展的自定义协议：

```typescript
{
  trustedOrigins: [
    "myapp://",                               // 移动应用协议
    "chrome-extension://YOUR_EXTENSION_ID",  // 浏览器扩展
    "exp://**",                               // 信任所有 Expo 开发 URL
    "exp://10.0.0.*:*/**"                    // 信任 IP 范围 10.0.0.x 及任意端口
  ]
}
```

### 动态来源列表 [#动态来源列表]

您也可以通过函数动态设置受信任来源列表：

```typescript
{
  trustedOrigins: async (request) => {
    const trustedOrigins = await queryTrustedDomains();
    return trustedOrigins;
  }
}
```

<Callout>
  **重要**：此函数将在每次传入请求时调用，因此如果您决定动态获取可信域名列表，请务必小心。
</Callout>

## 出站 OAuth 请求 [#出站-oauth-请求]

在登录过程中，Better Auth 会向 OAuth 和 OIDC 提供方端点发起服务器端请求：令牌交换、令牌刷新、令牌自省以及密钥集（JWKS）请求。这些请求不会跟随 HTTP 重定向。符合规范的提供方会以直接响应方式回答这些端点，并且绝不会重定向，因此标准集成不会受到影响。拒绝重定向可以防止提供方端点将服务器端请求引导到非预期的内部地址。

## 邮箱枚举保护 [#邮箱枚举保护]

Better Auth 在注册和更改邮箱端点防止邮箱枚举。当启用 `requireEmailVerification` 或 `autoSignIn` 设置为 `false` 时，注册端点对已注册和未注册邮箱返回相同的 `200` 响应，遵循 [OWASP 认证最佳实践](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#authentication-and-error-messages)。通过模拟密码哈希处理重复注册请求以减缓时间攻击。

配置细节请参见 [邮箱和密码 — 邮箱枚举保护](/docs/authentication/email-password#邮箱枚举保护)。

## 安全漏洞报告 [#安全漏洞报告]

如果您发现 Better Auth 存在安全漏洞，请通过 [GitHub Security Advisories](https://github.com/better-auth/better-auth/security/advisories/new) 进行报告。我们会及时处理所有报告，并为经验证的发现者提供致谢。

