azu/request-filtering-agent

GitHub: azu/request-filtering-agent

一个通过拦截私有和保留 IP 地址请求来防御 SSRF 攻击的 Node.js http(s).Agent 实现库。

Stars: 24 | Forks: 9

# request-filtering-agent [![Actions Status](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/a393712f90225956.svg)](https://github.com/azu/request-filtering-agent/actions) 一个用于拦截对 [私有 IP 地址](https://en.wikipedia.org/wiki/Private_network) 和 [保留 IP 地址](https://en.wikipedia.org/wiki/Reserved_IP_addresses) 请求的 [http(s).Agent](https://nodejs.org/api/http.html#http_class_http_agent) 类。 它有助于防止 [服务器端请求伪造 (SSRF)](https://en.wikipedia.org/wiki/Server-side_request_forgery) 攻击。 - [什么是 SSRF (服务器端请求伪造)?教程与示例](https://portswigger.net/web-security/ssrf) 此库依赖于 [ipaddr.js](https://github.com/whitequark/ipaddr.js) 的定义。 此库默认拦截发往以下 IP 地址的请求。 - [私有 IPv4 地址](https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses) - [私有 IPv6 地址](https://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses) - [链路本地地址](https://en.wikipedia.org/wiki/Private_network#Link-local_addresses) - [保留 IP 地址](https://en.wikipedia.org/wiki/Reserved_IP_addresses) 因此,此库会拦截发往非 `unicast` IP 地址的请求。 :warning: Node.js 内置的 `fetch` 不支持 `http.Agent`。 - [支持 nodejs/undici · Issue #23 · azu/request-filtering-agent](https://github.com/azu/request-filtering-agent/issues/23) ## 支持 `http.Agent` 的库 此库提供了 Node.js 的 [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) 实现。 [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) 受到流行库的支持。 - Node.js 内置的 `http` 和 `https` - [node-fetch](https://github.com/bitinn/node-fetch) - [node-http-proxy](https://github.com/http-party/node-http-proxy) - [axios](https://github.com/axios/axios) - [got](https://github.com/sindresorhus/got) - [@cypress/request](https://github.com/cypress-io/request) - :memo: [Request](https://github.com/request/request) 已被弃用,且存在 SSRF 问题 - [CVE-2023-28155 Request 允许通过攻击者控制的服务器进行跨协议重定向来绕过 SSRF 缓解措施 · Issue #3442 · request/request](https://github.com/request/request/issues/3442) - [Request 中的服务器端请求伪造 · CVE-2023-28155 · GitHub Advisory Database](https://github.com/advisories/GHSA-p8p7-x288-28g6) `request-filtering-agent` 可与这些库配合使用! ## 安装 使用 [npm](https://www.npmjs.com/) 安装: ``` npm install request-filtering-agent ``` ### 支持的 Node.js 版本 | 版本 | Node.js 14 | Node.js 16 | Node.js 18 | Node.js 20 | Node.js 22 | | :------ | :--------- | :--------- | :--------- | :--------- | :--------- | | v1.x.x | 支持 | 支持 | 支持 | 不支持 | 不支持 | | v2.x.x | 不支持 | 不支持 | 支持 | 支持 | 支持 | | v3.x.x | 不支持 | 不支持 | 不支持 | 支持 | 支持 | ## 用法 `useAgent(url, options)` 为该 url 返回一个 agent。 该 agent 默认拦截对 [私有网络](https://en.wikipedia.org/wiki/Private_network) 和 [保留 IP 地址](https://en.wikipedia.org/wiki/Reserved_IP_addresses) 的请求。 ``` const fetch = require("node-fetch"); const { useAgent } = require("request-filtering-agent"); const url = 'http://127.0.0.1:8080/'; fetch(url, { // use http or https agent for url agent: useAgent(url) }).catch(err => { console.err(err); // DNS lookup 127.0.0.1(family:4, host:127.0.0.1.nip.io) is not allowed. Because, It is private IP address. }); ``` `request-filtering-agent` 支持像 [nip.io](http://nip.io) 这样的环回域名。 此库会检测经过 DNS 查找的 IP 地址。 ``` $ dig 127.0.0.1.nip.io ;127.0.0.1.nip.io. IN A ;; ANSWER SECTION: 127.0.0.1.nip.io. 300 IN A 127.0.0.1 ``` 示例代码: ``` const fetch = require("node-fetch"); const { useAgent } = require("request-filtering-agent"); const url = 'http://127.0.0.1.nip.io:8080/'; fetch(url, { agent: useAgent(url) // use http or https agent for url }).catch(err => { console.err(err); // DNS lookup 127.0.0.1(family:4, host:127.0.0.1.nip.io) is not allowed. Because, It is private IP address. }); ``` 它将防止 [DNS 重绑定](https://en.wikipedia.org/wiki/DNS_rebinding) ## API ``` export interface RequestFilteringAgentOptions { // Allow to connect private IP address // This includes Private IP addresses and Reserved IP addresses. // https://en.wikipedia.org/wiki/Private_network // https://en.wikipedia.org/wiki/Reserved_IP_addresses // Example, http://127.0.0.1/, http://localhost/, https://169.254.169.254/ // Default: false allowPrivateIPAddress?: boolean; // Allow to connect meta address 0.0.0.0 // 0.0.0.0 (IPv4) and :: (IPv6) a meta address that routing another address // https://en.wikipedia.org/wiki/Reserved_IP_addresses // https://tools.ietf.org/html/rfc6890 // Default: false allowMetaIPAddress?: boolean; // Allow address list // It supports CIDR notation. // This values are preferred than denyAddressList // Default: [] allowIPAddressList?: string[]; // Deny address list // It supports CIDR notation. // Default: [] denyIPAddressList?: string[]; } /** * A subclass of http.Agent with request filtering */ export declare class RequestFilteringHttpAgent extends http.Agent { constructor(options?: http.AgentOptions & RequestFilteringAgentOptions); } /** * A subclass of https.Agent with request filtering */ export declare class RequestFilteringHttpsAgent extends https.Agent { constructor(options?: https.AgentOptions & RequestFilteringAgentOptions); } export declare const globalHttpAgent: RequestFilteringHttpAgent; export declare const globalHttpsAgent: RequestFilteringHttpsAgent; /** * Get an agent for the url * return http or https agent * @param url */ export declare const useAgent: (url: string, options?: https.AgentOptions & RequestFilteringAgentOptions) => RequestFilteringHttpAgent | RequestFilteringHttpsAgent; ``` ### 示例:创建带有选项的 Agent 一个允许请求 `127.0.0.1`,但禁止其他私有 IP 的 agent。 ``` const fetch = require("node-fetch"); const { RequestFilteringHttpAgent } = require("request-filtering-agent"); // Create http agent that allow 127.0.0.1, but it disallow other private ip const agent = new RequestFilteringHttpAgent({ allowIPAddressList: ["127.0.0.1"], // it is preferred than allowPrivateIPAddress option allowPrivateIPAddress: false, // Default: false }); // 127.0.0.1 is private ip address, but it is allowed const url = 'http://127.0.0.1:8080/'; fetch(url, { agent: agent }).then(res => { console.log(res); // OK }); // Allow requests to a specific CIDR range const agentWithCIDR = new RequestFilteringHttpAgent({ allowIPAddressList: ["192.168.1.0/24"], }); const urlInCIDR = 'http://192.168.1.1:8080/'; fetch(urlInCIDR, { agent: agentWithCIDR }).then(res => { console.log(res); // OK }); // Deny requests to a specific CIDR range const agentWithDenyCIDR = new RequestFilteringHttpAgent({ allowPrivateIPAddress: true, denyIPAddressList: ["192.168.1.0/24"], }); const urlInDenyCIDR = 'http://192.168.1.1:8080/'; fetch(urlInDenyCIDR, { agent: agentWithDenyCIDR }).catch(err => { console.err(err); // DNS lookup 192.168.1.1(family:4, host:192.168.1.1) is not allowed. Because It is defined in denyIPAddressList. }); ``` ## 相关 - [welefen/ssrf-agent: make http(s) request to prevent SSRF](https://github.com/welefen/ssrf-agent) - 它仅提供高级封装 - 它仅处理 [node-ip](https://github.com/indutny/node-ip/blob/43e442366bf5a93493c8c4c36736f87d675b0c3d/lib/ip.js#L302-L314) 中定义的私有 IP 地址 - 缺少像 `0.0.0.0` 这样的元 IP 地址 ## 更新日志 查看 [Releases 页面](https://github.com/azu/request-filtering-agent/releases)。 ## 运行测试 安装 devDependencies 并运行 `yarn test`: ``` yarn test ``` :memo: 此测试需要 IPv6 支持: - Travis CI: NG - GitHub Actions: OK ## 作者 - [github/azu](https://github.com/azu) - [twitter/azu_re](https://twitter.com/azu_re) ## 许可证 MIT © azu
标签:CISA项目, GNU通用公共许可证, HTTP代理, IPv4, IPv6, IP地址过滤, MITM代理, Node.js, PowerShell, SSRF防护, TLS, Web安全, 安全中间件, 服务端请求伪造, 白名单, 私有网络检测, 网络安全, 网络安全库, 自动化攻击, 自动化攻击, 蓝队分析, 请求过滤, 防御工具, 隐私保护, 黑名单