DEV Community

98IP Proxy
98IP Proxy

Posted on

Build a Redacted Diff Before Replaying Proxy Requests in DevTools

Chrome 152 DevTools can Resend XHR and other fetchable requests, and it can display binary request payloads as Hex, Base64, or UTF-8. The fastest safe habit is to create a redacted evidence record before you replay anything.

The record should answer: Did the status, timing, route, or payload fingerprint change? It should not contain a reusable secret.

Define an allowlist, not a denylist

Do not try to enumerate every possible secret header. Keep only fields you know are necessary.

const SAFE_HEADERS = new Set([
  "accept",
  "content-type",
  "content-length",
  "user-agent",
  "x-request-id",
]);

function safeHeaders(headers) {
  const out = {};

  for (const [name, value] of Object.entries(headers)) {
    const key = name.toLowerCase();
    if (SAFE_HEADERS.has(key)) out[key] = String(value);
  }

  return out;
}
Enter fullscreen mode Exit fullscreen mode

This excludes Authorization, Proxy-Authorization, cookies, CSRF tokens, signed URLs stored in custom headers, and vendor-specific credentials by default.

Fingerprint the body locally

For binary or compressed payloads, store a digest and byte length instead of the full body.

async function bodyEvidence(arrayBuffer) {
  const bytes = new Uint8Array(arrayBuffer);
  const digest = await crypto.subtle.digest("SHA-256", bytes);
  const sha256 = [...new Uint8Array(digest)]
    .map((byte) => byte.toString(16).padStart(2, "0"))
    .join("");

  return {
    bytes: bytes.byteLength,
    sha256,
  };
}
Enter fullscreen mode Exit fullscreen mode

Do not paste production payloads into an online hashing service. Compute the fingerprint in an approved local environment, then discard the raw copy when retention policy requires it.

Normalize one attempt

function normalizeAttempt(input) {
  return {
    capturedAtUtc: new Date(input.capturedAt).toISOString(),
    browserVersion: input.browserVersion,
    requestNumber: input.requestNumber,
    method: input.method,
    host: input.host,
    status: input.status,
    remoteAddressLabel: input.remoteAddressLabel,
    proxyRegion: input.proxyRegion,
    routeVerified: Boolean(input.routeVerified),
    timingMs: {
      queueing: input.timingMs.queueing,
      connect: input.timingMs.connect,
      ssl: input.timingMs.ssl,
      waiting: input.timingMs.waiting,
      total: input.timingMs.total,
    },
    headers: safeHeaders(input.headers),
    payload: input.payloadEvidence,
    result: input.result, // pass | fail | inconclusive
  };
}
Enter fullscreen mode Exit fullscreen mode

Use a label for the remote address if raw infrastructure details are not appropriate for the ticket. The important claim is whether the intended proxy route was verified and whether direct fallback was excluded.

Compare three attempts

Capture:

  1. the original failure;
  2. one unchanged DevTools resend;
  3. one single-variable test.
function diffAttempt(before, after) {
  const fields = [
    "status",
    "remoteAddressLabel",
    "proxyRegion",
    "routeVerified",
    "result",
  ];

  const changes = {};
  for (const field of fields) {
    if (before[field] !== after[field]) {
      changes[field] = { before: before[field], after: after[field] };
    }
  }

  for (const phase of Object.keys(before.timingMs)) {
    if (before.timingMs[phase] !== after.timingMs[phase]) {
      changes[`timingMs.${phase}`] = {
        before: before.timingMs[phase],
        after: after.timingMs[phase],
      };
    }
  }

  if (before.payload?.sha256 !== after.payload?.sha256) {
    changes.payloadSha256 = {
      before: before.payload?.sha256,
      after: after.payload?.sha256,
    };
  }

  return changes;
}
Enter fullscreen mode Exit fullscreen mode

Do not automate the actual resend for destructive methods. A human should review POST, PUT, PATCH, and DELETE side effects and use a sandbox or idempotency mechanism.

Interpret the result by layer

Signal First place to look
407 before destination headers Proxy authentication
Proxy certificate failure Browser-to-proxy TLS
Timeout before destination response DNS, network, or gateway
Destination 403 Application authorization or target policy
Destination 429 Rate limit; stop replaying
Success only in a warm tab Cookies, service worker, token, or connection state

Chrome 152 may represent the resend as a fetch() call. Record execution context and console originator; browser replay is not guaranteed to be byte-identical at the wire.

Minimum gate

  • Use an authorized test account and endpoint.
  • Replay only idempotent or duplicate-safe operations.
  • Keep a strict request budget.
  • Capture the original before changing anything.
  • Change one variable at a time.
  • Verify the proxy route and block direct fallback.
  • Store fingerprints, not credential-bearing bodies.
  • Mark uncertain results inconclusive.

Disclosure: I work with 98IP. We publish proxy engineering guides for authorized and policy-compliant testing. https://en.98ip.com/?k=dev

Top comments (0)