ja4

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 9, 2026 License: BSD-3-Clause, GPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package ja4 implements the JA4+ fingerprinting suite.

JA4+ is the successor to JA3, developed by FoxIO-LLC:

  • JA4: TLS Client Fingerprinting (BSD 3-Clause License)
  • JA4S: TLS Server Fingerprinting (FoxIO License 1.1)
  • JA4H: HTTP Client Fingerprinting (FoxIO License 1.1)
  • JA4X: X.509 Certificate Fingerprinting (FoxIO License 1.1)
  • JA4T: TCP Client Fingerprinting (FoxIO License 1.1)
  • JA4SSH: SSH Session Fingerprinting (FoxIO License 1.1)

JA4 addresses JA3's weakness to TLS extension randomization and adds QUIC support.

Reference: https://github.com/FoxIO-LLC/ja4 License: See LICENSE-JA4 file in this directory.

Index

Constants

View Source
const (
	ExtensionSNI  uint16 = 0  // Server Name Indication
	ExtensionALPN uint16 = 16 // Application-Layer Protocol Negotiation
)

TLS Extension types to exclude from JA4_c

View Source
const (
	DHCPOptionPad               = 0
	DHCPOptionSubnetMask        = 1
	DHCPOptionRouter            = 3
	DHCPOptionDNS               = 6
	DHCPOptionHostname          = 12
	DHCPOptionDomainName        = 15
	DHCPOptionBroadcast         = 28
	DHCPOptionNTPServers        = 42
	DHCPOptionRequestedIP       = 50
	DHCPOptionLeaseTime         = 51
	DHCPOptionMessageType       = 53
	DHCPOptionServerID          = 54
	DHCPOptionParamRequestList  = 55
	DHCPOptionMaxMsgSize        = 57
	DHCPOptionRenewalTime       = 58
	DHCPOptionRebindingTime     = 59
	DHCPOptionVendorClassID     = 60
	DHCPOptionClientID          = 61
	DHCPOptionDomainSearch      = 119
	DHCPOptionClasslessStaticRT = 121
	DHCPOptionEnd               = 255
)

DHCP Option Types

View Source
const (
	DHCPMsgTypeDiscover = 1
	DHCPMsgTypeOffer    = 2
	DHCPMsgTypeRequest  = 3
	DHCPMsgTypeDecline  = 4
	DHCPMsgTypeAck      = 5
	DHCPMsgTypeNak      = 6
	DHCPMsgTypeRelease  = 7
	DHCPMsgTypeInform   = 8
)

DHCP Message Types

View Source
const DefaultSSHSampleSize = 200

DefaultSSHSampleSize is the number of packets to sample for JA4SSH

Variables

View Source
var CommonOIDs = map[string]string{
	"550403":           "commonName",
	"550406":           "countryName",
	"550407":           "localityName",
	"550408":           "stateOrProvinceName",
	"55040a":           "organizationName",
	"55040b":           "organizationalUnitName",
	"551d0e":           "subjectKeyIdentifier",
	"551d0f":           "keyUsage",
	"551d11":           "subjectAltName",
	"551d13":           "basicConstraints",
	"551d1f":           "cRLDistributionPoints",
	"551d20":           "certificatePolicies",
	"551d23":           "authorityKeyIdentifier",
	"551d25":           "extKeyUsage",
	"2b0601050507010e": "authorityInfoAccess",
}

Common X.509 OID hex representations for reference

Functions

func ComputeJA4

func ComputeJA4(data *ClientHelloData) string

ComputeJA4 computes the JA4 fingerprint for a TLS ClientHello Format: {ja4_a}_{ja4_b}_{ja4_c} Example: t13d1516h2_8daaf6152771_e5627efa2ab1

func ComputeJA4D

func ComputeJA4D(data *DHCPv4Data) string

ComputeJA4D computes the JA4D fingerprint for a DHCPv4 packet Format: {ja4d_a}_{ja4d_b}_{ja4d_c} Example: d011412msh_8a2f3b4c5d6e_1234567890ab

ja4d_a (10 chars): {msg_type:1}{hw_type:2d}{prl_count:2d}{opt_count:2d}{vendor:2}{hostname:1} ja4d_b: 12-char truncated SHA256 of Parameter Request List values (comma-separated) ja4d_c: 12-char truncated SHA256 of sorted DHCP options (comma-separated)

func ComputeJA4DRaw

func ComputeJA4DRaw(data *DHCPv4Data) string

ComputeJA4DRaw returns the unhashed JA4D fingerprint for debugging

func ComputeJA4H

func ComputeJA4H(data *HTTPData) string

ComputeJA4H computes the JA4H fingerprint for an HTTP request Format: {method:2}{version:2}{cookie:1}{header_count:2}_{header_hash:12}_{cookie_hash:12}_{lang_hash:12} Example: ge11cn12_d6a4a8d71109_e0a89e3e939d_a82c9fccc4f7

func ComputeJA4HRaw

func ComputeJA4HRaw(data *HTTPData) string

ComputeJA4HRaw returns the unhashed JA4H fingerprint for debugging

func ComputeJA4L

func ComputeJA4L(latencyNanos int64, ttl uint8) string

ComputeJA4L computes the JA4L latency fingerprint. Format: {latency_ms}_{ttl}

Parameters:

  • latencyNanos: Latency in nanoseconds (SYN→SYN-ACK for JA4L-C, ClientHello→ServerHello for JA4L-S)
  • ttl: TTL value from the packet (used to estimate hop count/distance)

Returns empty string if latency is not available (≤0).

func ComputeJA4LMicro

func ComputeJA4LMicro(latencyNanos int64, ttl uint8) string

ComputeJA4LMicro computes the JA4L latency fingerprint with microsecond precision. Format: {latency_us}_{ttl}

This variant provides higher precision for low-latency networks.

func ComputeJA4S

func ComputeJA4S(data *ServerHelloData) string

ComputeJA4S computes the JA4S fingerprint for a TLS ServerHello Format: {ja4s_a}_{ja4s_b}_{ja4s_c} Where ja4s_a = protocol+version+extcount+alpn, ja4s_b = cipher hex, ja4s_c = hash of extensions

func ComputeJA4SSH

func ComputeJA4SSH(data *SSHStreamData) string

ComputeJA4SSH computes the JA4SSH fingerprint for an SSH session Format: c{mode_client}s{mode_server}_c{client_packets}s{server_packets}_c{client_acks}s{server_acks} Example: c76s76_c71s59_c0s70

func ComputeJA4T

func ComputeJA4T(data *TCPFingerprintData) string

ComputeJA4T computes the JA4T fingerprint for a TCP SYN packet (client) Format: {window_size}_{options}_{mss}_{window_scale} Example: 64240_2-1-3-1-1-4_1460_8

func ComputeJA4TS

func ComputeJA4TS(data *TCPFingerprintData) string

ComputeJA4TS computes the JA4TS fingerprint for a TCP SYN-ACK packet (server) Format: {window_size}_{options}_{mss}_{window_scale} Same format as JA4T but from server response

func ComputeJA4X

func ComputeJA4X(data *CertificateFingerprintData) string

ComputeJA4X computes the JA4X fingerprint for an X.509 certificate Format: {issuer_hash}_{subject_hash}_{extensions_hash} Each part is a 12-character truncated SHA256 hash

func ComputeJA4XFromCert

func ComputeJA4XFromCert(cert *x509.Certificate) string

ComputeJA4XFromCert computes the JA4X fingerprint directly from an x509.Certificate

func ComputeJA4XRaw

func ComputeJA4XRaw(data *CertificateFingerprintData) string

ComputeJA4XRaw returns the raw (unhashed) JA4X fingerprint

func DHCPMsgTypeName

func DHCPMsgTypeName(msgType uint8) string

DHCPMsgTypeName returns the human-readable name of a DHCP message type

func DetectSessionType

func DetectSessionType(fingerprint string) string

DetectSessionType analyzes JA4SSH fingerprint to detect session type

func ExtractHeaderOrder

func ExtractHeaderOrder(rawRequest []byte) ([]string, []string, string)

ExtractHeaderOrder extracts the order of HTTP headers from raw request bytes. This is needed because Go's net/http uses maps which randomize header order. Returns: header names in wire order, cookie field names in order, accept-language value

func ExtractTCPOptionsFromPacket

func ExtractTCPOptionsFromPacket(optionData []byte) []uint8

ExtractTCPOptionsFromPacket extracts TCP option types from raw option bytes

func FormatJA4

func FormatJA4(fingerprint string) string

FormatJA4 formats a JA4 fingerprint for display

func GetDHCPDeviceHint

func GetDHCPDeviceHint(data *DHCPv4Data) string

GetDHCPDeviceHint returns a hint about the device based on JA4D fingerprint characteristics

func GetOSHint

func GetOSHint(data *TCPFingerprintData) string

GetOSHint returns a hint about the OS based on JA4T fingerprint characteristics

func GetSupportedVersion

func GetSupportedVersion(extensions []uint16, supportedVersionsData []byte) uint16

GetSupportedVersion extracts the TLS 1.3 supported_versions value from extensions Returns 0 if not found

func IsPotentialReverseShell

func IsPotentialReverseShell(fingerprint string) bool

IsPotentialReverseShell checks if the JA4SSH pattern suggests a reverse shell

func IsSelfSignedByJA4X

func IsSelfSignedByJA4X(fingerprint string) bool

IsSelfSignedByJA4X checks if a certificate is likely self-signed based on JA4X A self-signed certificate has matching issuer and subject hashes

func JA4Raw

func JA4Raw(data *ClientHelloData) string

JA4Raw returns the raw (unhashed) JA4 fingerprint for debugging Format: {ja4_a}_{sorted_ciphers}_{sorted_extensions_signature_algorithms}

func ParseCipherSuites

func ParseCipherSuites(ciphers []int32) []uint16

ParseCipherSuites converts int32 slice to uint16 slice

func ParseExtensions

func ParseExtensions(extensions []int32) []uint16

ParseExtensions converts int32 slice to uint16 slice

func ParseJA4D

func ParseJA4D(fingerprint string) (msgType string, hwType int, prlCount, optCount int, vendor, hostname, prlHash, optHash string, err error)

ParseJA4D parses a JA4D fingerprint into its components Format: {msg_type:1}{hw_type:2d}{prl_count:2d}{opt_count:2d}{vendor:2}{hostname:1}

func ParseJA4H

func ParseJA4H(fingerprint string) (method, version, cookie string, headerCount int, headerHash, cookieHash, langHash string, err error)

ParseJA4H parses a JA4H fingerprint into its components

func ParseJA4SSH

func ParseJA4SSH(fingerprint string) (clientMode, serverMode, clientPkts, serverPkts, clientACKs, serverACKs int, ok bool)

ParseJA4SSH parses a JA4SSH fingerprint into its components

func ParseJA4T

func ParseJA4T(fingerprint string) (windowSize, mss, windowScale int, options []int, ok bool)

ParseJA4T parses a JA4T fingerprint into its components

func ValidateJA4

func ValidateJA4(fingerprint string) bool

ValidateJA4 checks if a JA4 fingerprint has the correct format

func ValidateJA4D

func ValidateJA4D(fingerprint string) bool

ValidateJA4D checks if a JA4D fingerprint has the correct format Format: {10 chars}_{12 chars}_{12 chars}

func ValidateJA4H

func ValidateJA4H(fingerprint string) bool

ValidateJA4H checks if a JA4H fingerprint has the correct format Format: {7 chars}_{12 chars}_{12 chars}_{12 chars}

func ValidateJA4S

func ValidateJA4S(fingerprint string) bool

ValidateJA4S checks if a JA4S fingerprint has the correct format Format: {ja4s_a}_{ja4s_b}_{ja4s_c}

func ValidateJA4SSH

func ValidateJA4SSH(fingerprint string) bool

ValidateJA4SSH checks if a JA4SSH fingerprint has the correct format

func ValidateJA4T

func ValidateJA4T(fingerprint string) bool

ValidateJA4T checks if a JA4T/JA4TS fingerprint has the correct format

func ValidateJA4X

func ValidateJA4X(fingerprint string) bool

ValidateJA4X checks if a JA4X fingerprint has the correct format

Types

type CertificateFingerprintData

type CertificateFingerprintData struct {
	IssuerRDNs    []string // Issuer RDN OIDs as hex strings
	SubjectRDNs   []string // Subject RDN OIDs as hex strings
	ExtensionOIDs []string // Extension OIDs as hex strings
}

CertificateFingerprintData contains the data needed to compute a JA4X fingerprint

func ExtractCertificateData

func ExtractCertificateData(cert *x509.Certificate) *CertificateFingerprintData

ExtractCertificateData extracts JA4X-relevant data from an x509.Certificate

func ExtractCertificateDataFromDER

func ExtractCertificateDataFromDER(der []byte) (*CertificateFingerprintData, error)

ExtractCertificateDataFromDER extracts JA4X-relevant data from DER-encoded certificate

type ClientHelloData

type ClientHelloData struct {
	Version             uint16   // TLS version from handshake
	CipherSuites        []uint16 // Cipher suites offered
	Extensions          []uint16 // Extensions present
	SNI                 string   // Server Name Indication
	ALPNs               []string // Application-Layer Protocol Negotiation values
	SupportedVers       uint16   // Supported versions extension value (for TLS 1.3)
	IsQUIC              bool     // Whether this is QUIC (not TCP/TLS)
	SignatureAlgorithms []uint16 // Signature algorithms from extension 13 (signature_algorithms)
}

ClientHelloData contains the data needed to compute a JA4 fingerprint

type DHCPv4Data

type DHCPv4Data struct {
	MessageType      uint8   // DHCP message type (DISCOVER, REQUEST, etc.)
	HardwareType     uint8   // Hardware type (1=Ethernet, 6=IEEE802, etc.)
	Options          []uint8 // All DHCP option types present (in wire order)
	ParamRequestList []uint8 // Parameter Request List (Option 55) values
	VendorClass      string  // Vendor Class Identifier (Option 60)
	Hostname         string  // Hostname (Option 12)
	ClientMAC        string  // Client MAC address (for tracking)
}

DHCPv4Data contains the data needed to compute a JA4D fingerprint

func BuildDHCPv4DataFromOptions

func BuildDHCPv4DataFromOptions(
	messageType uint8,
	hardwareType uint8,
	options []uint8,
	paramRequestList []uint8,
	vendorClass string,
	hostname string,
) *DHCPv4Data

BuildDHCPv4DataFromOptions builds DHCPv4Data from parsed DHCP options This is useful when the options have already been parsed (e.g., by gopacket)

func ExtractDHCPv4Data

func ExtractDHCPv4Data(messageType uint8, hardwareType uint8, optionBytes []byte) *DHCPv4Data

ExtractDHCPv4Data extracts JA4D data from raw DHCP option bytes The options should be the raw option bytes from the DHCP packet

type HTTPData

type HTTPData struct {
	Method         string   // HTTP method (GET, POST, etc.)
	Version        string   // HTTP version (1.0, 1.1, 2)
	HeaderOrder    []string // Headers in wire order (names only)
	HasCookie      bool     // Whether Cookie header is present
	CookieFields   []string // Cookie field names in order
	AcceptLanguage string   // Accept-Language header value
}

HTTPData contains the data needed to compute a JA4H fingerprint

func BuildHTTPDataFromRequest

func BuildHTTPDataFromRequest(req *http.Request, rawBytes []byte) *HTTPData

BuildHTTPDataFromRequest builds HTTPData from an http.Request and raw bytes The raw bytes are needed for header order preservation

func ExtractHTTPDataFromRaw

func ExtractHTTPDataFromRaw(rawRequest []byte) *HTTPData

ExtractHTTPDataFromRaw extracts JA4H data from raw HTTP request bytes This combines header order extraction with basic request line parsing

func ExtractHeaderOrderFromReader

func ExtractHeaderOrderFromReader(r *bufio.Reader) (*HTTPData, []byte, error)

ExtractHeaderOrderFromReader extracts header order from a bufio.Reader without consuming the entire buffer. Returns a new reader that can be used for subsequent parsing along with the extracted header data. This is useful when you want to extract header order before using http.ReadRequest

type SSHStreamData

type SSHStreamData struct {
	// Client packet payload lengths and their counts
	ClientPayloadCounts map[int]int
	// Server packet payload lengths and their counts
	ServerPayloadCounts map[int]int
	// Number of SSH packets from client
	ClientSSHPackets int
	// Number of SSH packets from server
	ServerSSHPackets int
	// Number of bare ACK packets from client
	ClientACKs int
	// Number of bare ACK packets from server
	ServerACKs int
}

SSHStreamData contains the data needed to compute JA4SSH fingerprints

func NewSSHStreamData

func NewSSHStreamData() *SSHStreamData

NewSSHStreamData creates a new SSHStreamData instance

func (*SSHStreamData) AddClientACK

func (s *SSHStreamData) AddClientACK()

AddClientACK records a client bare ACK

func (*SSHStreamData) AddClientPacket

func (s *SSHStreamData) AddClientPacket(payloadLen int)

AddClientPacket records a client SSH packet

func (*SSHStreamData) AddServerACK

func (s *SSHStreamData) AddServerACK()

AddServerACK records a server bare ACK

func (*SSHStreamData) AddServerPacket

func (s *SSHStreamData) AddServerPacket(payloadLen int)

AddServerPacket records a server SSH packet

func (*SSHStreamData) TotalPackets

func (s *SSHStreamData) TotalPackets() int

TotalPackets returns the total number of SSH packets seen

type ServerHelloData

type ServerHelloData struct {
	Version       uint16   // TLS version
	CipherSuite   uint16   // Selected cipher suite
	Extensions    []uint16 // Extensions present
	SupportedVers uint16   // Supported versions extension value (for TLS 1.3)
	IsQUIC        bool     // Whether this is QUIC
	ALPN          string   // Selected ALPN protocol
}

ServerHelloData contains the data needed to compute a JA4S fingerprint

type TCPFingerprintData

type TCPFingerprintData struct {
	WindowSize  uint16  // TCP Window Size
	Options     []uint8 // TCP Option types in order
	MSS         uint16  // Maximum Segment Size (Option 2)
	WindowScale uint8   // Window Scale factor (Option 3)
	IsSYN       bool    // Is this a SYN packet (client)
	IsSYNACK    bool    // Is this a SYN-ACK packet (server)
}

TCPFingerprintData contains the data needed to compute a JA4T/JA4TS fingerprint

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL