Unverified Commit e921134d authored by Hong Minhee's avatar Hong Minhee
Browse files

`lookupWebFinger()`: avoid infinite redirection

parent f8661ef9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -8,6 +8,10 @@ Version 1.0.14

To be released.

 -  Fixed a security vulnerability where the `lookupWebFinger()` function had
    followed the infinite number of redirects, which could lead to a denial of
    service attack.  Now it follows up to 5 redirects.


Version 1.0.13
--------------
+18 −0
Original line number Diff line number Diff line
import { assertEquals } from "@std/assert";
import { deadline } from "@std/async/deadline";
import * as mf from "mock_fetch";
import { test } from "../testing/mod.ts";
import type { ResourceDescriptor } from "./jrd.ts";
@@ -91,6 +92,23 @@ test("lookupWebFinger()", async (t) => {
    assertEquals(await lookupWebFinger("acct:johndoe@example.com"), expected);
  });

  mf.mock(
    "GET@/.well-known/webfinger",
    (_) =>
      new Response("", {
        status: 302,
        headers: { Location: "/.well-known/webfinger" },
      }),
  );

  await t.step("infinite redirection", async () => {
    const result = await deadline(
      lookupWebFinger("acct:johndoe@example.com"),
      2000,
    );
    assertEquals(result, null);
  });

  mf.uninstall();
});

+14 −1
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ import type { ResourceDescriptor } from "./jrd.ts";

const logger = getLogger(["fedify", "webfinger", "lookup"]);

const MAX_REDIRECTION = 5; // TODO: Make this configurable.

/**
 * Looks up a WebFinger resource.
 * @param resource The resource URL to look up.
@@ -26,6 +28,7 @@ export async function lookupWebFinger(
  }
  let url = new URL(`${protocol}//${server}/.well-known/webfinger`);
  url.searchParams.set("resource", resource.href);
  let redirected = 0;
  while (true) {
    logger.debug(
      "Fetching WebFinger resource descriptor from {url}...",
@@ -48,10 +51,20 @@ export async function lookupWebFinger(
      response.status >= 300 && response.status < 400 &&
      response.headers.has("Location")
    ) {
      url = new URL(
      redirected++;
      if (redirected >= MAX_REDIRECTION) {
        logger.error(
          "Too many redirections ({redirections}) while fetching WebFinger " +
            "resource descriptor.",
          { redirections: redirected },
        );
        return null;
      }
      const redirectedUrl = new URL(
        response.headers.get("Location")!,
        response.url == null || response.url === "" ? url : response.url,
      );
      url = redirectedUrl;
      continue;
    }
    if (!response.ok) {