From e24659d33a600f8e5e610d4074e46b1319e28440 Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 14 Jun 2026 20:07:56 +0200 Subject: [PATCH] docs: document sensitive headers and status transition (#11007) --- PRE_RELEASE_DOCS.md | 4 +-- README.md | 40 +++++++++++++++++++++--- docs/es/pages/advanced/request-config.md | 27 ++++++++++++++++ docs/es/pages/misc/security.md | 1 + docs/fr/pages/advanced/request-config.md | 27 ++++++++++++++++ docs/fr/pages/misc/security.md | 1 + docs/pages/advanced/request-config.md | 27 ++++++++++++++++ docs/pages/misc/security.md | 1 + docs/zh/pages/advanced/request-config.md | 27 ++++++++++++++++ docs/zh/pages/misc/security.md | 1 + 10 files changed, 149 insertions(+), 7 deletions(-) diff --git a/PRE_RELEASE_DOCS.md b/PRE_RELEASE_DOCS.md index c087de33..caeb164b 100644 --- a/PRE_RELEASE_DOCS.md +++ b/PRE_RELEASE_DOCS.md @@ -34,7 +34,7 @@ Do not store raw diffs or line-number-only instructions here; prefer stable sect - **Change:** Document the Node.js `sensitiveHeaders` request config option for stripping custom secret headers from cross-origin redirects. - **Source:** `PRE_RELEASE_CHANGELOG.md` Security Fixes, #10892. -- **Status:** Pending. +- **Status:** Applied. - **Docs targets:** `docs/pages/misc/security.md`; `docs/pages/advanced/request-config.md`; README request config section if it lists all config options; translated docs after English docs are finalized. - **Required content:** Explain that `sensitiveHeaders` is an optional array of custom secret-bearing header names. Matching is case-insensitive. The Node.js HTTP adapter removes matching headers only when following a redirect to a different origin. Same-origin redirects keep these headers. If `maxRedirects` is `0`, axios does not follow redirects and `sensitiveHeaders` is not used. Mention common custom authentication headers such as `X-API-Key`. - **Examples:** Include this request example. @@ -52,7 +52,7 @@ axios.get('https://api.example.com/users', { - **Change:** Document `transitional.validateStatusUndefinedResolves` for the `validateStatus: undefined` merge behavior. - **Source:** `PRE_RELEASE_CHANGELOG.md` Bug Fixes, #10899, closes #6688. -- **Status:** Pending. +- **Status:** Applied. - **Docs targets:** README request config section; `docs/pages/advanced/request-config.md` `validateStatus` section and request config example; translated request-config docs after English docs are finalized. - **Required content:** Explain that `validateStatus: undefined` keeps legacy behavior by default and resolves every response status because `transitional.validateStatusUndefinedResolves` defaults to `true`. Explain that setting `transitional.validateStatusUndefinedResolves` to `false` makes explicit `validateStatus: undefined` behave like the option was omitted, so axios uses the configured/default validator and rejects non-2xx responses by default. Mention that `validateStatus: null` still accepts every response status, and users who disable the transitional behavior should use `null` or `() => true` when they intentionally want all statuses to resolve. - **Examples:** Include a short opt-in example. diff --git a/README.md b/README.md index b0248d92..05e875f0 100644 --- a/README.md +++ b/README.md @@ -891,8 +891,11 @@ These config options are available for requests. Only `url` is required. Request redact: ['authorization', 'password'], // `validateStatus` defines whether to resolve or reject the promise for a given - // HTTP response status code. If `validateStatus` returns `true` (or is set to `null` - // or `undefined`), Axios resolves the promise; otherwise, Axios rejects it. + // HTTP response status code. If `validateStatus` returns `true` or is set to + // `null`, Axios resolves the promise; otherwise, Axios rejects it. + // Explicit `validateStatus: undefined` resolves every status by default for + // backward compatibility. Set `transitional.validateStatusUndefinedResolves` + // to `false` to make explicit `undefined` behave as if this option was omitted. validateStatus: function (status) { return status >= 200 && status < 300; // default }, @@ -902,9 +905,9 @@ These config options are available for requests. Only `url` is required. Request maxRedirects: 21, // default // `sensitiveHeaders` (Node only option) lists custom secret-bearing headers - // to remove from cross-origin redirects. Matching is case-insensitive. - // Same-origin redirects keep these headers. If `maxRedirects` is 0, this - // option is not used. + // (such as `X-API-Key`) to remove from cross-origin redirects. Matching is + // case-insensitive. Same-origin redirects keep these headers. If + // `maxRedirects` is 0, this option is not used. sensitiveHeaders: ['X-API-Key'], // `beforeRedirect` defines a function that Axios calls before redirect. @@ -1042,6 +1045,11 @@ These config options are available for requests. Only `url` is required. Request // throw ETIMEDOUT error instead of generic ECONNABORTED on request timeouts clarifyTimeoutError: false, + // keep explicit `validateStatus: undefined` resolving every response status + // for backward compatibility. Set to false to make explicit undefined behave + // as if validateStatus was omitted. + validateStatusUndefinedResolves: true, + // advertise `zstd` in the default Accept-Encoding header when the current // Node.js runtime supports zstd decompression. Axios still decompresses // zstd responses when support exists and `decompress` is true. @@ -1072,6 +1080,15 @@ These config options are available for requests. Only `url` is required. Request } ``` +For custom secret-bearing headers in Node.js, list them in `sensitiveHeaders` so Axios removes them when following a redirect to another origin: + +```js +axios.get('https://api.example.com/users', { + headers: { 'X-API-Key': 'secret' }, + sensitiveHeaders: ['X-API-Key'] +}); +``` + ### Strict RFC 3986 percent-encoding for query params By default, axios decodes `%3A`, `%24`, `%2C` and `%20` back to `:`, `$`, `,` and `+` for readability (the `+` follows the `application/x-www-form-urlencoded` convention for spaces in query strings). These characters are valid in a query component under [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-3.4), so the default output is correct, but some backends require strict percent-encoding and reject the readable form. @@ -1410,6 +1427,19 @@ axios.get('/user/12345', { }); ``` +By default, explicit `validateStatus: undefined` keeps legacy behavior and resolves every response status because `transitional.validateStatusUndefinedResolves` defaults to `true`. Set it to `false` to make explicit `validateStatus: undefined` behave like the option was omitted, so Axios uses the configured/default validator and rejects non-2xx responses by default. + +`validateStatus: null` still accepts every response status. If you disable the transitional behavior and intentionally want all statuses to resolve, use `null` or `() => true`. + +```js +axios.get('/user/12345', { + validateStatus: undefined, + transitional: { + validateStatusUndefinedResolves: false + } +}); +``` + Use `toJSON` to get more information about the HTTP error. ```js diff --git a/docs/es/pages/advanced/request-config.md b/docs/es/pages/advanced/request-config.md index 1be43430..2a713765 100644 --- a/docs/es/pages/advanced/request-config.md +++ b/docs/es/pages/advanced/request-config.md @@ -265,10 +265,34 @@ axios.get('/user/12345', { La función `validateStatus` te permite sobreescribir la validación predeterminada del código de estado. Por defecto, axios rechazará la Promise si el código de estado no está en el rango 200-299. Puedes sobreescribir este comportamiento proporcionando una función `validateStatus` personalizada. La función debe devolver `true` si el código de estado está dentro del rango que deseas aceptar. +Por defecto, un `validateStatus: undefined` explícito conserva el comportamiento heredado y resuelve todos los estados de respuesta, porque `transitional.validateStatusUndefinedResolves` tiene `true` como valor predeterminado. Establece `transitional.validateStatusUndefinedResolves` en `false` si quieres que un `validateStatus: undefined` explícito se comporte como si `validateStatus` se hubiera omitido; así axios usa el validador configurado/predeterminado y rechaza las respuestas que no sean 2xx por defecto. + +`validateStatus: null` sigue aceptando todos los estados de respuesta. Si desactivas el comportamiento transicional y quieres intencionalmente resolver todos los estados, usa `validateStatus: null` o un validador que devuelva `true`. + +```js +axios.get('/user/12345', { + validateStatus: undefined, + transitional: { + validateStatusUndefinedResolves: false + } +}); +``` + ### `maxRedirects` La propiedad `maxRedirects` define el número máximo de redirecciones a seguir. Si se establece en 0, no se seguirá ninguna redirección. +### `sensitiveHeaders` + +La propiedad `sensitiveHeaders` es un arreglo opcional de nombres de encabezados personalizados que contienen secretos, como `X-API-Key`, que el adaptador HTTP de Node.js elimina al seguir una redirección a un origen diferente. La coincidencia no distingue mayúsculas/minúsculas. Las redirecciones al mismo origen conservan estos encabezados. Si `maxRedirects` es `0`, axios no sigue redirecciones y `sensitiveHeaders` no se usa. + +```js +axios.get('https://api.example.com/users', { + headers: { 'X-API-Key': 'secret' }, + sensitiveHeaders: ['X-API-Key'] +}); +``` + ### `beforeRedirect` La función `beforeRedirect` te permite modificar la solicitud antes de que sea redirigida. Úsala para ajustar las opciones de la solicitud al redirigir, para inspeccionar los últimos encabezados de respuesta, o para cancelar la solicitud lanzando un error. Si `maxRedirects` se establece en 0, `beforeRedirect` no se usa. @@ -381,6 +405,7 @@ La propiedad `transitional` te permite habilitar o deshabilitar ciertas caracter - `forcedJSONParsing`: Fuerza a axios a analizar la cadena de respuesta como JSON incluso si `responseType` no es `'json'`. - `clarifyTimeoutError`: Clarifica el mensaje de error cuando una solicitud expira. Es útil cuando depuras problemas de timeout. +- `validateStatusUndefinedResolves`: Si se establece en `true` _(predeterminado)_, un `validateStatus: undefined` explícito resuelve todos los estados de respuesta por compatibilidad. Establécelo en `false` para tratar `undefined` explícito como si `validateStatus` se hubiera omitido, de modo que axios use el validador configurado/predeterminado. Usa `validateStatus: null` o un validador que devuelva `true` cuando quieras intencionalmente resolver todos los estados. - `advertiseZstdAcceptEncoding`: Cuando se establece en `true`, axios añade `zstd` al encabezado `Accept-Encoding` predeterminado cuando el runtime actual de Node.js soporta descompresión zstd. Las respuestas zstd se descomprimen automáticamente cuando son compatibles y `decompress` es `true`. - `legacyInterceptorReqResOrdering`: Cuando se establece en `true`, se usará el orden de solicitud/respuesta de interceptores heredado. @@ -477,6 +502,7 @@ La propiedad `maxRate` define el **ancho de banda** máximo (en bytes por segund return status >= 200 && status < 300; }, maxRedirects: 21, + sensitiveHeaders: ['X-API-Key'], beforeRedirect: (options, { headers }) => { if (options.hostname === "typicode.com") { options.auth = "user:password"; @@ -507,6 +533,7 @@ La propiedad `maxRate` define el **ancho de banda** máximo (en bytes por segund silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false, + validateStatusUndefinedResolves: true, advertiseZstdAcceptEncoding: false, legacyInterceptorReqResOrdering: true, }, diff --git a/docs/es/pages/misc/security.md b/docs/es/pages/misc/security.md index d0776a6a..c58091aa 100644 --- a/docs/es/pages/misc/security.md +++ b/docs/es/pages/misc/security.md @@ -27,6 +27,7 @@ Las siguientes opciones de configuración de solicitud tienen implicaciones dire | --- | --- | --- | | [`socketPath`](/pages/advanced/request-config#socketpath) | Si proviene de entrada no confiable, un atacante puede redirigir el tráfico a sockets locales privilegiados como `/var/run/docker.sock`, eludiendo las protecciones SSRF basadas en hostname (CWE-918). | Filtra o restringe con allowlist las claves de configuración provenientes de entradas no confiables. Usa [`allowedSocketPaths`](/pages/advanced/request-config#allowedsocketpaths) para restringir las rutas de socket aceptadas. | | [`beforeRedirect`](/pages/advanced/request-config#beforeredirect) | Se ejecuta después de que `follow-redirects` elimina las credenciales en una bajada de protocolo. Reinyectar credenciales sin verificar el protocolo de destino puede filtrarlas sobre HTTP en texto plano. | Reinyecta credenciales únicamente para destinos HTTPS de confianza. Verifica `options.protocol === "https:"` antes de asignar `auth`. | +| [`sensitiveHeaders`](/pages/advanced/request-config#sensitiveheaders) | Encabezados secretos personalizados como `X-API-Key` pueden reenviarse por el adaptador HTTP de Node.js al seguir redirecciones a un origen diferente. | Lista esos nombres de encabezado en `sensitiveHeaders`; axios elimina las coincidencias sin distinguir mayúsculas/minúsculas en redirecciones de origen cruzado. Las redirecciones al mismo origen los conservan. | | [`withXSRFToken`](/pages/advanced/request-config#withxsrftoken) | Establecerlo en `true` fuerza el encabezado XSRF en solicitudes de origen cruzado. Versiones anteriores de axios lo habilitaban implícitamente con `withCredentials: true`; las versiones más recientes requieren ambos indicadores. | Déjalo en `undefined` (solo mismo origen) salvo que tu backend valide explícitamente XSRF en solicitudes de origen cruzado. | | [`redact`](/pages/advanced/request-config#redact) | `AxiosError#toJSON()` incluye la configuración de la solicitud por defecto, lo que puede filtrar encabezados `Authorization` o credenciales `auth` en logs y telemetría de errores. | Pasa un arreglo `redact` con los nombres de claves de configuración sensibles. La coincidencia es insensible a mayúsculas y recursiva. | | [`formDataHeaderPolicy`](/pages/advanced/request-config#formdataheaderpolicy) | Un `FormData` personalizado cuyo `getHeaders()` devuelve valores controlados por un atacante puede sobrescribir encabezados como `Authorization` o inyectar otros arbitrarios en Node.js. | Establece `'content-only'` para copiar únicamente `Content-Type` y `Content-Length`, y luego define los demás encabezados explícitamente a través de la configuración `headers` de la solicitud. | diff --git a/docs/fr/pages/advanced/request-config.md b/docs/fr/pages/advanced/request-config.md index 365020f7..ce0ef14d 100644 --- a/docs/fr/pages/advanced/request-config.md +++ b/docs/fr/pages/advanced/request-config.md @@ -265,10 +265,34 @@ axios.get('/user/12345', { La fonction `validateStatus` vous permet de remplacer la validation du code de statut par défaut. Par défaut, axios rejette la promise si le code de statut n'est pas dans la plage 200-299. Vous pouvez remplacer ce comportement en fournissant une fonction `validateStatus` personnalisée. La fonction doit retourner `true` si le code de statut est dans la plage que vous souhaitez accepter. +Par défaut, définir explicitement `validateStatus: undefined` conserve le comportement historique et résout tous les statuts de réponse, car `transitional.validateStatusUndefinedResolves` vaut `true` par défaut. Définissez `transitional.validateStatusUndefinedResolves` à `false` si vous voulez qu'un `validateStatus: undefined` explicite se comporte comme si `validateStatus` était omis : axios utilise alors le validateur configuré/par défaut et rejette les réponses non-2xx par défaut. + +`validateStatus: null` accepte toujours tous les statuts de réponse. Si vous désactivez le comportement de transition et souhaitez intentionnellement résoudre tous les statuts, utilisez `validateStatus: null` ou un validateur qui retourne `true`. + +```js +axios.get('/user/12345', { + validateStatus: undefined, + transitional: { + validateStatusUndefinedResolves: false + } +}); +``` + ### `maxRedirects` La propriété `maxRedirects` définit le nombre maximum de redirections à suivre. Si défini à 0, aucune redirection ne sera suivie. +### `sensitiveHeaders` + +La propriété `sensitiveHeaders` est un tableau optionnel de noms d'en-têtes personnalisés contenant des secrets, comme `X-API-Key`, que l'adaptateur HTTP Node.js retire lorsqu'il suit une redirection vers une origine différente. La correspondance est insensible à la casse. Les redirections same-origin conservent ces en-têtes. Si `maxRedirects` vaut `0`, axios ne suit pas les redirections et `sensitiveHeaders` n'est pas utilisée. + +```js +axios.get('https://api.example.com/users', { + headers: { 'X-API-Key': 'secret' }, + sensitiveHeaders: ['X-API-Key'] +}); +``` + ### `beforeRedirect` La fonction `beforeRedirect` vous permet de modifier la requête avant qu'elle ne soit redirigée. Utilisez-la pour ajuster les options de requête lors d'une redirection, inspecter les derniers en-têtes de réponse, ou annuler la requête en levant une erreur. Si `maxRedirects` est défini à 0, `beforeRedirect` n'est pas utilisé. @@ -381,6 +405,7 @@ La propriété `transitional` vous permet d'activer ou de désactiver certaines - `forcedJSONParsing` : Force axios à analyser la chaîne de réponse comme du JSON même si `responseType` n'est pas `'json'`. - `clarifyTimeoutError` : Clarifie le message d'erreur lorsqu'une requête expire. Utile lors du débogage de problèmes de délai d'attente. +- `validateStatusUndefinedResolves` : Si défini à `true` _(par défaut)_, un `validateStatus: undefined` explicite résout tous les statuts de réponse pour préserver la compatibilité. Définissez à `false` pour traiter `undefined` explicite comme si `validateStatus` était omis, afin qu'axios utilise le validateur configuré/par défaut. Utilisez `validateStatus: null` ou un validateur qui retourne `true` lorsque vous voulez intentionnellement résoudre tous les statuts. - `advertiseZstdAcceptEncoding` : Lorsqu'elle vaut `true`, axios ajoute `zstd` à l'en-tête `Accept-Encoding` par défaut lorsque le runtime Node.js actuel prend en charge la décompression zstd. Les réponses zstd sont tout de même décompressées automatiquement lorsqu'elles sont prises en charge et que `decompress` vaut `true`. - `legacyInterceptorReqResOrdering` : Lorsque défini à true, l'ordre hérité de traitement requête/réponse des intercepteurs sera utilisé. @@ -477,6 +502,7 @@ La propriété `maxRate` définit la **bande passante** maximale (en octets par return status >= 200 && status < 300; }, maxRedirects: 21, + sensitiveHeaders: ['X-API-Key'], beforeRedirect: (options, { headers }) => { if (options.hostname === "typicode.com") { options.auth = "user:password"; @@ -507,6 +533,7 @@ La propriété `maxRate` définit la **bande passante** maximale (en octets par silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false, + validateStatusUndefinedResolves: true, advertiseZstdAcceptEncoding: false, legacyInterceptorReqResOrdering: true, }, diff --git a/docs/fr/pages/misc/security.md b/docs/fr/pages/misc/security.md index 47dfb12d..703af9ea 100644 --- a/docs/fr/pages/misc/security.md +++ b/docs/fr/pages/misc/security.md @@ -27,6 +27,7 @@ Les options de configuration de requête suivantes ont des implications directes | --- | --- | --- | | [`socketPath`](/pages/advanced/request-config#socketpath) | Si dérivée d'une entrée non fiable, un attaquant peut rediriger le trafic vers des sockets locaux privilégiés tels que `/var/run/docker.sock`, contournant les protections SSRF basées sur le hostname (CWE-918). | Filtrez ou créez une liste blanche des clés de configuration provenant d'entrées non fiables. Utilisez [`allowedSocketPaths`](/pages/advanced/request-config#allowedsocketpaths) pour restreindre les chemins de socket acceptés. | | [`beforeRedirect`](/pages/advanced/request-config#beforeredirect) | S'exécute après que `follow-redirects` ait retiré les identifiants en cas de rétrogradation de protocole. Réinjecter des identifiants sans vérifier le protocole de destination peut les exposer en HTTP en clair. | Ne réinjectez les identifiants que pour des destinations HTTPS de confiance. Vérifiez `options.protocol === "https:"` avant d'assigner `auth`. | +| [`sensitiveHeaders`](/pages/advanced/request-config#sensitiveheaders) | Des en-têtes secrets personnalisés comme `X-API-Key` peuvent être transmis par l'adaptateur HTTP Node.js lors d'une redirection vers une origine différente. | Listez ces noms d'en-têtes dans `sensitiveHeaders` ; axios retire les correspondances sans tenir compte de la casse lors des redirections cross-origin. Les redirections same-origin les conservent. | | [`withXSRFToken`](/pages/advanced/request-config#withxsrftoken) | La définir à `true` force l'en-tête XSRF sur les requêtes cross-origin. Les anciennes versions d'axios l'activaient implicitement avec `withCredentials: true` ; les versions plus récentes nécessitent les deux indicateurs. | Laissez à `undefined` (same-origin uniquement) sauf si votre backend valide explicitement XSRF sur les requêtes cross-origin. | | [`redact`](/pages/advanced/request-config#redact) | `AxiosError#toJSON()` inclut la configuration de requête par défaut, ce qui peut faire fuiter des en-têtes `Authorization` ou des identifiants `auth` dans les logs d'erreurs et la télémétrie. | Passez un tableau `redact` avec les noms de clés de configuration sensibles. La correspondance est insensible à la casse et récursive. | | [`formDataHeaderPolicy`](/pages/advanced/request-config#formdataheaderpolicy) | Un `FormData` personnalisé dont `getHeaders()` retourne des valeurs contrôlées par un attaquant peut écraser des en-têtes comme `Authorization` ou en injecter des arbitraires dans Node.js. | Définissez `'content-only'` pour ne copier que `Content-Type` et `Content-Length`, puis définissez les autres en-têtes explicitement via la configuration `headers` de la requête. | diff --git a/docs/pages/advanced/request-config.md b/docs/pages/advanced/request-config.md index cfdd537f..2a32a808 100644 --- a/docs/pages/advanced/request-config.md +++ b/docs/pages/advanced/request-config.md @@ -265,10 +265,34 @@ axios.get('/user/12345', { The `validateStatus` function allows you to override the default status code validation. By default, axios will reject the promise if the status code is not in the range of 200-299. You can override this behavior by providing a custom `validateStatus` function. The function should return `true` if the status code is within the range you want to accept. +By default, explicit `validateStatus: undefined` keeps legacy behavior and resolves every response status because `transitional.validateStatusUndefinedResolves` defaults to `true`. Set `transitional.validateStatusUndefinedResolves` to `false` when you want an explicit `validateStatus: undefined` to behave as if `validateStatus` was omitted, so axios uses the configured/default validator and rejects non-2xx responses by default. + +`validateStatus: null` still accepts every response status. If you disable the transitional behavior and intentionally want all statuses to resolve, use `validateStatus: null` or a validator that returns `true`. + +```js +axios.get('/user/12345', { + validateStatus: undefined, + transitional: { + validateStatusUndefinedResolves: false + } +}); +``` + ### `maxRedirects` The `maxRedirects` property defines the maximum number of redirects to follow. If set to 0, no redirects will be followed. +### `sensitiveHeaders` + +The `sensitiveHeaders` property is an optional array of custom secret-bearing header names, such as `X-API-Key`, that the Node.js HTTP adapter removes when following a redirect to a different origin. Matching is case-insensitive. Same-origin redirects keep these headers. If `maxRedirects` is `0`, axios does not follow redirects and `sensitiveHeaders` is not used. + +```js +axios.get('https://api.example.com/users', { + headers: { 'X-API-Key': 'secret' }, + sensitiveHeaders: ['X-API-Key'] +}); +``` + ### `beforeRedirect` The `beforeRedirect` function allows you to modify the request before it is redirected. Use this to adjust the request options upon redirecting, to inspect the latest response headers, or to cancel the request by throwing an error. If maxRedirects is set to 0, `beforeRedirect` is not used. @@ -381,6 +405,7 @@ The `transitional` property allows you to enable or disable certain transitional - `forcedJSONParsing`: Forces axios to parse the response string as JSON even if `responseType` is not `'json'`. - `clarifyTimeoutError`: Clarifies the error message when a request times out. This is useful when you are debugging timeout issues. +- `validateStatusUndefinedResolves`: If set to `true` _(default)_, explicit `validateStatus: undefined` resolves every response status for backward compatibility. Set to `false` to treat explicit `undefined` as if `validateStatus` was omitted, so axios uses the configured/default validator. Use `validateStatus: null` or a validator that returns `true` when you intentionally want all statuses to resolve. - `advertiseZstdAcceptEncoding`: When set to `true`, axios adds `zstd` to the default `Accept-Encoding` request header when the current Node.js runtime supports zstd decompression. zstd responses are still decompressed automatically when supported and `decompress` is `true`. - `legacyInterceptorReqResOrdering`: When set to true we will use the legacy interceptor request/response ordering. @@ -477,6 +502,7 @@ The `maxRate` property defines the maximum **bandwidth** (in bytes per second) f return status >= 200 && status < 300; }, maxRedirects: 21, + sensitiveHeaders: ['X-API-Key'], beforeRedirect: (options, { headers }) => { if (options.hostname === "typicode.com") { options.auth = "user:password"; @@ -507,6 +533,7 @@ The `maxRate` property defines the maximum **bandwidth** (in bytes per second) f silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false, + validateStatusUndefinedResolves: true, advertiseZstdAcceptEncoding: false, legacyInterceptorReqResOrdering: true, }, diff --git a/docs/pages/misc/security.md b/docs/pages/misc/security.md index 0ff6d48a..349b706d 100644 --- a/docs/pages/misc/security.md +++ b/docs/pages/misc/security.md @@ -27,6 +27,7 @@ The following request-config options have direct security implications. They are | --- | --- | --- | | [`socketPath`](/pages/advanced/request-config#socketpath) | If derived from untrusted input, an attacker can redirect traffic to privileged local sockets like `/var/run/docker.sock`, bypassing hostname-based SSRF protections (CWE-918). | Strip or allowlist config keys from untrusted input. Use [`allowedSocketPaths`](/pages/advanced/request-config#allowedsocketpaths) to restrict accepted socket paths. | | [`beforeRedirect`](/pages/advanced/request-config#beforeredirect) | Runs after `follow-redirects` strips credentials on protocol downgrade. Re-injecting credentials without checking the destination protocol can leak them over plain HTTP. | Only re-add credentials for trusted HTTPS destinations. Check `options.protocol === "https:"` before assigning `auth`. | +| [`sensitiveHeaders`](/pages/advanced/request-config#sensitiveheaders) | Custom secret headers such as `X-API-Key` can be forwarded by the Node.js HTTP adapter when following redirects to a different origin. | List custom secret-bearing header names in `sensitiveHeaders`; axios removes matching headers case-insensitively on cross-origin redirects. Same-origin redirects keep them. | | [`withXSRFToken`](/pages/advanced/request-config#withxsrftoken) | Setting `true` forces the XSRF header on cross-origin requests. Older axios versions implicitly enabled this with `withCredentials: true`; newer versions require both flags. | Leave at `undefined` (same-origin only) unless your backend explicitly validates XSRF on cross-origin requests. | | [`redact`](/pages/advanced/request-config#redact) | `AxiosError#toJSON()` includes the request config by default, which can leak `Authorization` headers or `auth` credentials into error logs and telemetry. | Pass a `redact` array with sensitive config key names. Matching is case-insensitive and recursive. | | [`formDataHeaderPolicy`](/pages/advanced/request-config#formdataheaderpolicy) | A custom `FormData` whose `getHeaders()` returns attacker-controlled values can overwrite headers like `Authorization` or inject arbitrary ones in Node.js. | Set `'content-only'` to copy only `Content-Type` and `Content-Length`, then set other headers explicitly via the request `headers` config. | diff --git a/docs/zh/pages/advanced/request-config.md b/docs/zh/pages/advanced/request-config.md index cfeb3240..3ad2c8be 100644 --- a/docs/zh/pages/advanced/request-config.md +++ b/docs/zh/pages/advanced/request-config.md @@ -265,10 +265,34 @@ axios.get('/user/12345', { `validateStatus` 函数允许你覆盖默认的状态码验证逻辑。默认情况下,axios 会在状态码不在 200-299 范围内时拒绝 Promise。你可以提供自定义的 `validateStatus` 函数来覆盖此行为,该函数应在状态码在你希望接受的范围内时返回 `true`。 +默认情况下,显式设置 `validateStatus: undefined` 会保留旧行为并 resolve 所有响应状态码,因为 `transitional.validateStatusUndefinedResolves` 默认值为 `true`。如果希望显式的 `validateStatus: undefined` 表现得像未设置 `validateStatus` 一样,请将 `transitional.validateStatusUndefinedResolves` 设置为 `false`;这样 axios 会使用已配置/默认的验证器,并默认拒绝非 2xx 响应。 + +`validateStatus: null` 仍会接受所有响应状态码。如果你禁用了该过渡行为,但确实希望所有状态码都 resolve,请使用 `validateStatus: null` 或返回 `true` 的验证器。 + +```js +axios.get('/user/12345', { + validateStatus: undefined, + transitional: { + validateStatusUndefinedResolves: false + } +}); +``` + ### `maxRedirects` `maxRedirects` 属性定义最大重定向次数,设置为 0 时不跟随任何重定向。 +### `sensitiveHeaders` + +`sensitiveHeaders` 属性是一个可选数组,用于列出承载密钥的自定义请求头名称(例如 `X-API-Key`)。Node.js HTTP 适配器在跟随重定向到不同源时会移除这些请求头。匹配不区分大小写。同源重定向会保留这些请求头。如果 `maxRedirects` 为 `0`,axios 不会跟随重定向,`sensitiveHeaders` 也不会使用。 + +```js +axios.get('https://api.example.com/users', { + headers: { 'X-API-Key': 'secret' }, + sensitiveHeaders: ['X-API-Key'] +}); +``` + ### `beforeRedirect` `beforeRedirect` 函数允许你在请求重定向前对其进行修改,可用于调整重定向时的请求选项、检查最新的响应头或通过抛出错误来取消请求。当 `maxRedirects` 设置为 0 时,不会使用 `beforeRedirect`。 @@ -381,6 +405,7 @@ proxy: { - `forcedJSONParsing`:强制 axios 将响应解析为 JSON,即使响应不是有效的 JSON。适用于返回无效 JSON 的 API。 - `clarifyTimeoutError`:在请求超时时提供更清晰的错误信息,适用于调试超时问题。 +- `validateStatusUndefinedResolves`:若设置为 `true` _(默认)_,显式的 `validateStatus: undefined` 会出于兼容性 resolve 所有响应状态码。设置为 `false` 后,显式的 `undefined` 会像未设置 `validateStatus` 一样处理,axios 将使用已配置/默认的验证器。如果你确实希望所有状态码都 resolve,请使用 `validateStatus: null` 或返回 `true` 的验证器。 - `advertiseZstdAcceptEncoding`:设为 `true` 时,如果当前 Node.js 运行时支持 zstd 解压,axios 会在默认 `Accept-Encoding` 请求头中加入 `zstd`。在受支持且 `decompress` 为 `true` 时,zstd 响应仍会自动解压。 - `legacyInterceptorReqResOrdering`:设置为 true 时使用旧版拦截器请求/响应排序。 @@ -477,6 +502,7 @@ proxy: { return status >= 200 && status < 300; }, maxRedirects: 21, + sensitiveHeaders: ['X-API-Key'], beforeRedirect: (options, { headers }) => { if (options.hostname === "typicode.com") { options.auth = "user:password"; @@ -507,6 +533,7 @@ proxy: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false, + validateStatusUndefinedResolves: true, advertiseZstdAcceptEncoding: false, legacyInterceptorReqResOrdering: true, }, diff --git a/docs/zh/pages/misc/security.md b/docs/zh/pages/misc/security.md index dab058e3..fef47050 100644 --- a/docs/zh/pages/misc/security.md +++ b/docs/zh/pages/misc/security.md @@ -27,6 +27,7 @@ axios.defaults.maxBodyLength = 10 * 1024 * 1024; | --- | --- | --- | | [`socketPath`](/pages/advanced/request-config#socketpath) | 如果取自不可信输入,攻击者可将流量重定向到 `/var/run/docker.sock` 等特权本地套接字,绕过基于主机名的 SSRF 防护(CWE-918)。 | 对来自不可信输入的配置进行过滤或仅允许特定键。使用 [`allowedSocketPaths`](/pages/advanced/request-config#allowedsocketpaths) 限制可接受的套接字路径。 | | [`beforeRedirect`](/pages/advanced/request-config#beforeredirect) | 在 `follow-redirects` 因协议降级剥离凭据**之后**运行。如果不检查目标协议就重新注入凭据,可能在明文 HTTP 上泄露凭据。 | 仅对可信的 HTTPS 目标重新添加凭据。在为 `auth` 赋值前检查 `options.protocol === "https:"`。 | +| [`sensitiveHeaders`](/pages/advanced/request-config#sensitiveheaders) | `X-API-Key` 等自定义密钥请求头在 Node.js HTTP 适配器跟随重定向到不同源时可能被转发。 | 在 `sensitiveHeaders` 中列出这些自定义密钥请求头名称;axios 会在跨源重定向时不区分大小写地移除匹配项。同源重定向会保留它们。 | | [`withXSRFToken`](/pages/advanced/request-config#withxsrftoken) | 设置为 `true` 会在跨域请求中强制设置 XSRF 请求头。较旧的 axios 版本会在 `withCredentials: true` 时隐式启用此行为;新版本要求两个标志同时设置。 | 保持为 `undefined`(仅同源),除非你的后端确实在跨域请求中校验 XSRF。 | | [`redact`](/pages/advanced/request-config#redact) | `AxiosError#toJSON()` 默认会包含请求配置,可能将 `Authorization` 请求头或 `auth` 凭据泄露到错误日志和遥测中。 | 通过 `redact` 数组传入需要遮蔽的配置键名。匹配不区分大小写,且会递归处理。 | | [`formDataHeaderPolicy`](/pages/advanced/request-config#formdataheaderpolicy) | 自定义 `FormData` 的 `getHeaders()` 若返回攻击者可控的值,可能在 Node.js 中覆盖 `Authorization` 等请求头或注入任意请求头。 | 设置为 `'content-only'` 仅复制 `Content-Type` 与 `Content-Length`,再通过请求 `headers` 配置显式设置其他请求头。 |