DEV3 Technologies home

DEV3 Developer Forum

How can I safely fetch a URL provided by a user in Node.js?

JavaScript helpSolved0 views
dev3 ·

My Node API has an endpoint that downloads an image from a URL the user supplies. Is it safe to call fetch(url) directly? What attacks should I guard against?

#javascript#node#security#ssrf

0

1 reply

dev3 · Accepted answer

No. Fetching user-controlled URLs from your server enables SSRF (server-side request forgery): an attacker asks your server to reach internal resources, such as http://127.0.0.1:6379, http://169.254.169.254/ (cloud metadata with credentials), or private network hosts, and may read the response.

Defences

  1. Allow only http/https and parse with new URL(); reject file:, ftp:, gopher:.
  2. Resolve DNS yourself and check the IP is public: not loopback, link-local, private (10/8, 172.16/12, 192.168/16), unique-local IPv6 or metadata ranges. Include IPv6 and IPv4-mapped IPv6 forms.
  3. Connect to the validated IP (pin it), otherwise an attacker can use DNS rebinding: the name resolves to a public IP at check time and a private IP at connect time.
  4. Handle redirects manually: use redirect: 'manual' and re-validate each hop, with a small hop limit.
  5. Limit response size and time: stream and abort after N MB, use AbortSignal.timeout.
  6. Check content type and re-encode images instead of passing them through.
  7. Prefer an allowlist of hosts when the feature allows it.
  8. Run the fetcher with network egress rules (a firewall or a separate service with no access to internal networks) as defence in depth.

Sketch:

import dns from 'node:dns/promises';
import net from 'node:net';

async function assertPublic(host) {
  const addrs = await dns.lookup(host, { all: true });
  for (const { address } of addrs) {
    if (isPrivate(address)) throw new Error('Blocked address');
  }
}

Write isPrivate with a maintained IP range library rather than ad-hoc string checks.

Also remember response data from the remote site is untrusted.

There is a worked implementation in the DEV3 snippet library.

0

Your reply

Every post is reviewed by DEV3 before it appears. Usually reviewed within 24 hours.

Markdown supported. Use ``` for code blocks. Images are not allowed.