summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/HttpRequestService.ts
diff options
context:
space:
mode:
authorrectcoordsystem <heohyun73@gmail.com>2024-11-06 05:31:11 +0900
committerJulia Johannesen <julia@insertdomain.name>2024-11-20 19:17:25 -0500
commitf36f4b5398561dcf7365729c530f5b1868c6b994 (patch)
tree6ec5c6abd7794318caed54e43caa72e887386848 /packages/backend/src/core/HttpRequestService.ts
parentfix: Try using `CacheService` to avoid excess db lookups (diff)
downloadsharkey-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.ts90
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,