> ## Documentation Index
> Fetch the complete documentation index at: https://docs.infrawatch.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Fingerprinting

> Cluster related services using JA4, certificate structure, and content hashes

Fingerprints turn protocol behaviour into stable values that are useful for
clustering related infrastructure. They help you pivot when IP addresses,
domains, and certificates change.

<img src="https://mintcdn.com/infrawatch/JNVa1KeNiEbAN82u/images/sections/fingerprints.svg?fit=max&auto=format&n=JNVa1KeNiEbAN82u&q=85&s=828c1ecd02448ebaf9bcac081ede911f" alt="Several observed services connected by a shared fingerprint" className="rounded-2xl" width="640" height="320" data-path="images/sections/fingerprints.svg" />

Infrawatch extracts fingerprints from observed services and exposes them as
typed InfraQL fields. A fingerprint is evidence of shared behaviour, not proof
that two systems have the same owner.

There are two independent families. Behavioural fingerprints describe **how a
service talks**. Content hashes describe **what it served**. They fail in
different ways, which is what makes combining them a strong pivot: an operator
who changes their TLS stack usually keeps their page, and an operator who
rewrites their page usually keeps their stack.

## The JA4 suite

Behavioural fingerprints, derived from the handshake and protocol exchange.

| Fingerprint | What it represents          | InfraQL field                     |
| ----------- | --------------------------- | --------------------------------- |
| JA4         | TLS client handshake        | `fingerprints.ja4`                |
| JA4S        | TLS server response         | `fingerprints.ja4s`               |
| JA4H        | HTTP behaviour              | `fingerprints.ja4h`               |
| JA4T        | TCP transport behaviour     | `fingerprints.ja4t`               |
| JA4N        | Network behaviour           | `fingerprints.ja4n`               |
| JA3S        | Legacy TLS server response  | `fingerprints.ja3s`               |
| HASSH       | SSH server behaviour        | `fingerprints.hasshs`             |
| JA4X        | X.509 certificate structure | `tls.leaf_certificate.ja4x.value` |

<Note>
  Not every protocol produces every fingerprint. A field is present only when
  the corresponding handshake, response, or certificate was observable.
</Note>

### MCP toolsets

An MCP server is identified by what it can do, so its toolset is hashed into a
fingerprint of its own:

| Fingerprint | What it represents                     | InfraQL field                     |
| ----------- | -------------------------------------- | --------------------------------- |
| MCP toolset | The set of tools an MCP server exposes | `fingerprints.mcp_toolset_sha256` |

Two servers sharing this value are running the same toolset, which is how you
find every deployment of one MCP server across the internet, whoever stood it
up. Pair it with [AI surface](/external-surface/ai-surface) to see the same
class of exposure inside your own project.

## Content hashes

Hashes over what the service actually returned. These survive infrastructure
changes that break a behavioural fingerprint, so they are the better pivot when
an operator moves hosts but redeploys the same application.

Most are objects rather than single strings, carrying six algorithms each:

```text theme={null}
http.response.favicons.hash.sha256="<sha256>"
```

Available algorithms are `md5`, `sha1`, `sha256`, `murmur3`, `ssdeep`, and
`tlsh`. `murmur3` matches the favicon-style hashes used by other tooling, and
`ssdeep` and `tlsh` are both fuzzy, so near-identical content still clusters.

Reach for a fuzzy hash when an exact one stops matching. A single injected
tracking script or a changed timestamp breaks `sha256` completely, while
`ssdeep` and `tlsh` still place the two pages together.

### From the response

Captured from the HTTP response itself, so these are present whether or not the
page was rendered. Each has a twin under `http.redirects.*` for the hops taken
on the way.

| Hash                    | What it covers                                                                                                                                       | InfraQL field                                                |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Favicon                 | The site icon, plus its URL, filename, declared size, and link rel                                                                                   | `http.response.favicons.hash`                                |
| Response body           | The captured response body                                                                                                                           | `http.response.body.hash`                                    |
| Headers                 | SHA-256 over normalized headers, lowercased names with sorted values                                                                                 | `http.response.headers_hash`                                 |
| DOM structure           | SHA-256 over HTML tag names in traversal order. A structure hash, so text and attribute changes do not affect it and a re-themed copy still matches. | `http.response.body.html.dom_hash`                           |
| Form signatures         | Canonical per-form signatures, each `<METHOD> [ordered_control_types]`                                                                               | `http.response.body.html.form_signatures_hash`               |
| External script domains | Hostnames the page loads scripts from                                                                                                                | `http.response.body.html.external_script_domains_hash`       |
| External script paths   | Path patterns of those scripts                                                                                                                       | `http.response.body.html.external_script_path_patterns_hash` |

<Tip>
  Favicon hashing is the cheapest pivot in the product. An operator rebuilds the
  site, changes hosting, and reissues the certificate, then ships the same icon
  they have used for years.
</Tip>

### From the rendered page

Captured only when the service was rendered in a browser.

| Hash                    | What it covers                                  | InfraQL field                                                      |
| ----------------------- | ----------------------------------------------- | ------------------------------------------------------------------ |
| Rendered DOM            | The DOM as the browser built it                 | `http.browser.rendered_page.dom_hash`                              |
| Rendered text           | Visible text of the rendered page               | `http.browser.rendered_page.text_hash`                             |
| Response bodies         | Bodies returned by the page's own requests      | `http.browser.transactions.response_hash`                          |
| Console output          | Text written to the browser console             | `http.browser.console.text_hash`                                   |
| Downloads               | Files the page caused to be downloaded          | `http.browser.downloads.hash`                                      |
| Storage values and keys | What the page left in browser storage           | `http.browser.storage.value_hash`, `http.browser.storage.key_hash` |
| Cookie values           | Cookies the page set                            | `http.browser.cookies.value_hash`                                  |
| Page identifiers        | Analytics and tag identifiers found in the page | `http.browser.identifiers.value_hash`                              |
| WebSocket frames        | Payloads sent over WebSocket connections        | `http.browser.websockets.frames.payload_hash`                      |

### Screenshots

The screenshot carries the usual six algorithms plus a perceptual hash for
visual similarity, which matches pages that *look* the same even when nothing
about their markup does:

| Hash                    | InfraQL field                    |
| ----------------------- | -------------------------------- |
| Screenshot bytes        | `http.screenshot.hash`           |
| Perceptual hash (pHash) | `http.screenshot.perpetual_hash` |

<Warning>
  The perceptual hash field is spelled `perpetual_hash`. A query written as
  `perceptual_hash` will not match anything.
</Warning>

### Certificates

| Hash                  | InfraQL field                      |
| --------------------- | ---------------------------------- |
| Leaf certificate      | `tls.leaf_certificate.hashes`      |
| Leaf certificate DER  | `tls.leaf_certificate.der.hashes`  |
| Certificate chain     | `tls.certificate_chain.hashes`     |
| Certificate chain DER | `tls.certificate_chain.der.hashes` |

<Note>
  Only the `http.browser.*` hashes require a rendered observation. Favicon,
  response body, header, and HTML structure hashes are taken from the response
  itself, so they are present on services that were never rendered.
</Note>

### Find a redeployed application

The DOM hash ignores text, so it catches the same kit rebranded across hosts:

```text theme={null}
same_service(
  services.http.browser.rendered_page.dom_hash.sha256="<sha256>"
  AND services.last_seen>=now-30d
)
```

Combine a content hash with a behavioural one to raise confidence:

```text theme={null}
same_service(
  services.http.browser.rendered_page.dom_hash.sha256="<sha256>"
  AND services.fingerprints.ja4s="t13d1516h2_8daaf6152771"
)
```

## Find the same server stack

Search services for an exact JA4S value:

```text theme={null}
fingerprints.ja4s="t13d1516h2_8daaf6152771"
```

When searching hosts, prefix the service field and keep the conditions on one
endpoint:

```text theme={null}
same_service(
  services.fingerprints.ja4s="t13d1516h2_8daaf6152771"
  AND services.transport_protocol:tcp
  AND services.port:443
)
```

Add a time condition to focus on current infrastructure:

```text theme={null}
same_service(
  services.fingerprints.ja4s="t13d1516h2_8daaf6152771"
  AND services.last_seen>=now-7d
)
```

## Pivot on certificate structure

JA4X describes the ordered structure of an X.509 certificate rather than its
contents. It is useful for finding certificates created by the same tooling
even when subjects, serial numbers, or keys differ.

Search the complete JA4X value:

```text theme={null}
tls.leaf_certificate.ja4x.value="a1b2c3d4e5f6_112233445566_abcdef123456"
```

Or search one component independently:

```text theme={null}
tls.leaf_certificate.ja4x.issuer_rdn_hash="a1b2c3d4e5f6"
```

The available components are:

* `issuer_rdn_hash`
* `subject_rdn_hash`
* `extension_oid_hash`

## Measure stack diversity

Host records expose `distinct_ja4s`, the number of different JA4S values across
the host's current services. Large values can reveal shared hosting, gateways,
or a host serving several distinct TLS stacks.

```text theme={null}
distinct_ja4s>3
```

## Build a stronger pivot

Fingerprint matches are most useful when combined with independent evidence:

```text theme={null}
same_service(
  services.fingerprints.ja4s="t13d1516h2_8daaf6152771"
  AND services.http.title:"Control Panel"
  AND services.country_code:DE
)
```

Use ASN, certificate, HTTP, tag, and observation-time fields to reduce false
positives before attributing infrastructure.

<CardGroup cols={2}>
  <Card title="Service fields" icon="https://mintcdn.com/infrawatch/gCEz_Bv1hOrMPG8n/images/products/data-dictionary.svg?fit=max&auto=format&n=gCEz_Bv1hOrMPG8n&q=85&s=7610d618bf3603732c6f9102b62101df" href="/data-dictionary/services" width="32" height="32" data-path="images/products/data-dictionary.svg">
    Browse every searchable fingerprint and protocol field.
  </Card>

  <Card title="Correlate services" icon="https://mintcdn.com/infrawatch/gCEz_Bv1hOrMPG8n/images/products/correlation.svg?fit=max&auto=format&n=gCEz_Bv1hOrMPG8n&q=85&s=b42684cb60cccb048d9d37dce7024886" href="/infraql/correlation" width="32" height="32" data-path="images/products/correlation.svg">
    Keep related conditions on the same observed service.
  </Card>
</CardGroup>
