diff options
| author | rectcoordsystem <heohyun73@gmail.com> | 2024-11-06 05:31:11 +0900 |
|---|---|---|
| committer | Julia Johannesen <julia@insertdomain.name> | 2024-11-20 19:17:25 -0500 |
| commit | f36f4b5398561dcf7365729c530f5b1868c6b994 (patch) | |
| tree | 6ec5c6abd7794318caed54e43caa72e887386848 /packages/backend/src/core/HttpRequestService.ts | |
| parent | fix: Try using `CacheService` to avoid excess db lookups (diff) | |
| download | sharkey-f36f4b5398561dcf7365729c530f5b1868c6b994.tar.gz sharkey-f36f4b5398561dcf7365729c530f5b1868c6b994.tar.bz2 sharkey-f36f4b5398561dcf7365729c530f5b1868c6b994.zip | |
fix(backend): check target IP before sending HTTP request
Diffstat (limited to 'packages/backend/src/core/HttpRequestService.ts')
| -rw-r--r-- | packages/backend/src/core/HttpRequestService.ts | 90 |
1 files changed, 88 insertions, 2 deletions
diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index 08e9f46b2d..6c013eacc0 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -6,6 +6,7 @@ import * as http from 'node:http'; import * as https from 'node:https'; import * as net from 'node:net'; +import ipaddr from 'ipaddr.js'; import CacheableLookup from 'cacheable-lookup'; import fetch from 'node-fetch'; import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent'; @@ -26,6 +27,91 @@ export type HttpRequestSendOptions = { }; @Injectable() +class HttpRequestServiceAgent extends http.Agent { + constructor( + @Inject(DI.config) + private config: Config, + + options?: Object + ) { + super(options); + } + + @bindThis + public createConnection(options: Object, callback?: Function): net.Socket { + const socket = super.createConnection(options, callback) + .on('connect', ()=>{ + const address = socket.remoteAddress; + if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') { + if (address && ipaddr.isValid(address)) { + if (this.isPrivateIp(address)) { + socket.destroy(new Error(`Blocked address: ${address}`)); + } + } + } + }); + return socket; + }; + + @bindThis + private isPrivateIp(ip: string): boolean { + const parsedIp = ipaddr.parse(ip); + + for (const net of this.config.allowedPrivateNetworks ?? []) { + const cidr = ipaddr.parseCIDR(net); + if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) { + return false; + } + } + + return parsedIp.range() !== 'unicast'; + } +} + +@Injectable() +class HttpsRequestServiceAgent extends https.Agent { + constructor( + @Inject(DI.config) + private config: Config, + + options?: Object + ) { + super(options); + } + + @bindThis + public createConnection(options: Object, callback?: Function): net.Socket { + const socket = super.createConnection(options, callback) + .on('connect', ()=>{ + const address = socket.remoteAddress; + if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') { + if (address && ipaddr.isValid(address)) { + if (this.isPrivateIp(address)) { + socket.destroy(new Error(`Blocked address: ${address}`)); + } + } + } + }); + return socket; + }; + + @bindThis + private isPrivateIp(ip: string): boolean { + const parsedIp = ipaddr.parse(ip); + + for (const net of this.config.allowedPrivateNetworks ?? []) { + const cidr = ipaddr.parseCIDR(net); + if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) { + return false; + } + } + + return parsedIp.range() !== 'unicast'; + } +} + + +@Injectable() export class HttpRequestService { /** * Get http non-proxy agent @@ -57,14 +143,14 @@ export class HttpRequestService { lookup: false, // nativeのdns.lookupにfallbackしない }); - this.http = new http.Agent({ + this.http = new HttpRequestServiceAgent(config, { keepAlive: true, keepAliveMsecs: 30 * 1000, lookup: cache.lookup as unknown as net.LookupFunction, localAddress: config.outgoingAddress, }); - this.https = new https.Agent({ + this.https = new HttpsRequestServiceAgent(config, { keepAlive: true, keepAliveMsecs: 30 * 1000, lookup: cache.lookup as unknown as net.LookupFunction, |