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
- Variables
- func ComputeJA4(data *ClientHelloData) string
- func ComputeJA4D(data *DHCPv4Data) string
- func ComputeJA4DRaw(data *DHCPv4Data) string
- func ComputeJA4H(data *HTTPData) string
- func ComputeJA4HRaw(data *HTTPData) string
- func ComputeJA4L(latencyNanos int64, ttl uint8) string
- func ComputeJA4LMicro(latencyNanos int64, ttl uint8) string
- func ComputeJA4S(data *ServerHelloData) string
- func ComputeJA4SSH(data *SSHStreamData) string
- func ComputeJA4T(data *TCPFingerprintData) string
- func ComputeJA4TS(data *TCPFingerprintData) string
- func ComputeJA4X(data *CertificateFingerprintData) string
- func ComputeJA4XFromCert(cert *x509.Certificate) string
- func ComputeJA4XRaw(data *CertificateFingerprintData) string
- func DHCPMsgTypeName(msgType uint8) string
- func DetectSessionType(fingerprint string) string
- func ExtractHeaderOrder(rawRequest []byte) ([]string, []string, string)
- func ExtractTCPOptionsFromPacket(optionData []byte) []uint8
- func FormatJA4(fingerprint string) string
- func GetDHCPDeviceHint(data *DHCPv4Data) string
- func GetOSHint(data *TCPFingerprintData) string
- func GetSupportedVersion(extensions []uint16, supportedVersionsData []byte) uint16
- func IsPotentialReverseShell(fingerprint string) bool
- func IsSelfSignedByJA4X(fingerprint string) bool
- func JA4Raw(data *ClientHelloData) string
- func ParseCipherSuites(ciphers []int32) []uint16
- func ParseExtensions(extensions []int32) []uint16
- func ParseJA4D(fingerprint string) (msgType string, hwType int, prlCount, optCount int, ...)
- func ParseJA4H(fingerprint string) (method, version, cookie string, headerCount int, ...)
- func ParseJA4SSH(fingerprint string) (clientMode, serverMode, clientPkts, serverPkts, clientACKs, serverACKs int, ...)
- func ParseJA4T(fingerprint string) (windowSize, mss, windowScale int, options []int, ok bool)
- func ValidateJA4(fingerprint string) bool
- func ValidateJA4D(fingerprint string) bool
- func ValidateJA4H(fingerprint string) bool
- func ValidateJA4S(fingerprint string) bool
- func ValidateJA4SSH(fingerprint string) bool
- func ValidateJA4T(fingerprint string) bool
- func ValidateJA4X(fingerprint string) bool
- type CertificateFingerprintData
- type ClientHelloData
- type DHCPv4Data
- type HTTPData
- type SSHStreamData
- type ServerHelloData
- type TCPFingerprintData
Constants ¶
const ( ExtensionSNI uint16 = 0 // Server Name Indication ExtensionALPN uint16 = 16 // Application-Layer Protocol Negotiation )
TLS Extension types to exclude from JA4_c
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
const ( DHCPMsgTypeDiscover = 1 DHCPMsgTypeOffer = 2 DHCPMsgTypeRequest = 3 DHCPMsgTypeDecline = 4 DHCPMsgTypeAck = 5 DHCPMsgTypeNak = 6 DHCPMsgTypeRelease = 7 DHCPMsgTypeInform = 8 )
DHCP Message Types
const DefaultSSHSampleSize = 200
DefaultSSHSampleSize is the number of packets to sample for JA4SSH
Variables ¶
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 ¶
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 ¶
ComputeJA4HRaw returns the unhashed JA4H fingerprint for debugging
func ComputeJA4L ¶
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 ¶
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 ¶
DHCPMsgTypeName returns the human-readable name of a DHCP message type
func DetectSessionType ¶
DetectSessionType analyzes JA4SSH fingerprint to detect session type
func ExtractHeaderOrder ¶
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 ¶
ExtractTCPOptionsFromPacket extracts TCP option types from raw option bytes
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 ¶
GetSupportedVersion extracts the TLS 1.3 supported_versions value from extensions Returns 0 if not found
func IsPotentialReverseShell ¶
IsPotentialReverseShell checks if the JA4SSH pattern suggests a reverse shell
func IsSelfSignedByJA4X ¶
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 ¶
ParseCipherSuites converts int32 slice to uint16 slice
func ParseExtensions ¶
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 ValidateJA4 ¶
ValidateJA4 checks if a JA4 fingerprint has the correct format
func ValidateJA4D ¶
ValidateJA4D checks if a JA4D fingerprint has the correct format Format: {10 chars}_{12 chars}_{12 chars}
func ValidateJA4H ¶
ValidateJA4H checks if a JA4H fingerprint has the correct format Format: {7 chars}_{12 chars}_{12 chars}_{12 chars}
func ValidateJA4S ¶
ValidateJA4S checks if a JA4S fingerprint has the correct format Format: {ja4s_a}_{ja4s_b}_{ja4s_c}
func ValidateJA4SSH ¶
ValidateJA4SSH checks if a JA4SSH fingerprint has the correct format
func ValidateJA4T ¶
ValidateJA4T checks if a JA4T/JA4TS fingerprint has the correct format
func ValidateJA4X ¶
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 ¶
BuildHTTPDataFromRequest builds HTTPData from an http.Request and raw bytes The raw bytes are needed for header order preservation
func ExtractHTTPDataFromRaw ¶
ExtractHTTPDataFromRaw extracts JA4H data from raw HTTP request bytes This combines header order extraction with basic request line parsing
func ExtractHeaderOrderFromReader ¶
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