UNPKG

request-filtering-agent

Version:

An http(s).Agent implementation that block request Private IP address.

211 lines (158 loc) 7.87 kB
# request-filtering-agent [![Actions Status](https://github.com/azu/request-filtering-agent/workflows/ci/badge.svg)](https://github.com/azu/request-filtering-agent/actions) An [http(s).Agent](https://nodejs.org/api/http.html#http_class_http_agent) class block the request to [Private IP addresses](https://en.wikipedia.org/wiki/Private_network) and [Reserved IP addresses](https://en.wikipedia.org/wiki/Reserved_IP_addresses). It helps to prevent [server-side request forgery (SSRF)](https://en.wikipedia.org/wiki/Server-side_request_forgery) attack. - [What is SSRF (Server-side request forgery)? Tutorial & Examples](https://portswigger.net/web-security/ssrf) This library depends on [ipaddr.js](https://github.com/whitequark/ipaddr.js) definitions. This library blocks the request to these IP addresses by default. - [Private IPv4 addresses](https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses) - [Private IPv6 addresses](https://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses) - [Link-local addresses](https://en.wikipedia.org/wiki/Private_network#Link-local_addresses) - [Reserved IP addresses](https://en.wikipedia.org/wiki/Reserved_IP_addresses) So, This library block the request to non-`unicast` IP addresses. :warning: Node.js's built-in `fetch` does not support `http.Agent`. - [Passing a custom agent to `fetch()` · Issue #1489 · nodejs/undici](https://github.com/nodejs/undici/issues/1489) ## Support `http.Agent` libraries This library provides Node.js's [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) implementation. [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) is supported by popular library. - Node.js's built-in `http` and `https` - [node-fetch](https://github.com/bitinn/node-fetch) - [Request](https://github.com/request/request) - :memo: `request`'s `agent` may be insecure - [CVE-2023-28155 Request allows a bypass of SSRF mitigations via an attacker-controller server that does a cross-protocol redirect · Issue #3442 · request/request](https://github.com/request/request/issues/3442) - [Server-Side Request Forgery in Request · CVE-2023-28155 · GitHub Advisory Database](https://github.com/advisories/GHSA-p8p7-x288-28g6) - [node-http-proxy](https://github.com/http-party/node-http-proxy) - [axios](https://github.com/axios/axios) - [got](https://github.com/sindresorhus/got) `request-filtering-agent` works with these libraries! ## Install Install with [npm](https://www.npmjs.com/): npm install request-filtering-agent ### Support Node.js version | Version | Node.js 12 | Node.js 14 | Node.js 16 | Node.js 18 | Node.js 20 | | :------ | :--------- | :--------- | :--------- | :--------- | :---------- | | v1.x.x | Support | Support | Support | Support | Not Support | | v2.0.0 | No Support | No Support | No Support | Support | Support | ## Usage `useAgent(url, options)` return an agent for the url. The agent blocks the request to [Private network](https://en.wikipedia.org/wiki/Private_network) and [Reserved IP addresses](https://en.wikipedia.org/wiki/Reserved_IP_addresses) by default. ```js 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` support loopback domain like [nip.io](http://nip.io). This library detects the IP address that is dns lookup-ed. ``` $ 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 ``` Example code: ```js 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. }); ``` It will prevent [DNS rebinding](https://en.wikipedia.org/wiki/DNS_rebinding) ## API ```ts 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 // This values are preferred than denyAddressList // Default: [] allowIPAddressList?: string[]; // Deny address list // 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; ``` ### Example: Create an Agent with options An agent that allow requesting `127.0.0.1`, but it disallows other Private IP. ```js 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 }); ``` ## Related - [welefen/ssrf-agent: make http(s) request to prevent SSRF](https://github.com/welefen/ssrf-agent) - It provides only high level wrapper - It only handles Private IP address that is definition in [node-ip](https://github.com/indutny/node-ip/blob/43e442366bf5a93493c8c4c36736f87d675b0c3d/lib/ip.js#L302-L314) - Missing Meta IP Address like `0.0.0.0` ## Changelog See [Releases page](https://github.com/azu/request-filtering-agent/releases). ## Running tests Install devDependencies and Run `yarn test`: yarn test :memo: This testing require IPv6 supports: - Travis CI: NG - GitHub Actions: OK ## Contributing Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/azu/request-filtering-agent/issues). For security issue, please see [SECURITY.md](./SECURITY.md) 1. Fork it! 2. Create your feature branch: `git checkout -b my-new-feature` 3. Commit your changes: `git commit -am 'Add some feature'` 4. Push to the branch: `git push origin my-new-feature` 5. Submit a pull request :D ## Author - [github/azu](https://github.com/azu) - [twitter/azu_re](https://twitter.com/azu_re) ## License MIT © azu