-
Notifications
You must be signed in to change notification settings - Fork 2
/
ja4h.irule
106 lines (97 loc) · 3.4 KB
/
ja4h.irule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
###############################################################################################
# iRule to calculate JA4H "HTTP Request"
# See JA4H spec on GitHub for more details
# https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4H.md
#
# Copyright (c) 2024, FoxIO, LLC.
# All rights reserved.
# Licensed under FoxIO License 1.1
# For full license text and more details, see the repo root https://github.com/FoxIO-LLC/ja4
###############################################################################################
when CLIENT_ACCEPTED {
# Use these variables to define the -r (raw) and -o (original) switches defined in the JA4 spec
# 0 = false/disabled (default) and 1 = true/enabled
set ja4h_raw 1
set ja4h_original 0
}
when HTTP_REQUEST priority 10 {
#Collect JA4H "a" values
set me [string range [string tolower [HTTP::method]] 0 1]
set v [string map {"." ""} [HTTP::version]]
set c "n"
set r "n"
if { [HTTP::header exists "cookie"] } {
set c "c"
}
if { [HTTP::header exists "referer"] } {
set r "r"
}
set lang "0000"
if { [set alval [HTTP::header value "accept-language"]] ne "" } {
if { $alval contains ";" } {
set alval [string range $alval 0 [string first ";" $alval]]
}
set alval [string tolower [string range [string map {"-" ""} ${alval}] 0 3]]
set lang [string replace $lang 0 [string length ${alval}] ${alval}]
}
#Collect JA4H "b" values
set hc 0
set hstr ""
foreach hname [HTTP::header names] {
if { ${hname} starts_with "X-JA4" } {
continue
} elseif { ([string tolower ${hname}] eq "cookie") || ([string tolower ${hname}] eq "referer")} {
if { ${ja4h_original} }{
append hstr "${hname},"
}
} else {
incr hc
append hstr "${hname},"
}
}
if { $hc > 99 } {
set hc 99
}
set hc [format "%02d" $hc]
set hstr [string trimright ${hstr} ","]
binary scan [sha256 ${hstr}] H* hhash
set trunc_hhash [string range $hhash 0 11]
#Collect JA4H "c" and "d" values
set cstr ""
set clist [list]
set ckvstr ""
#set ckvlist [list]
foreach cname [HTTP::cookie names] {
lappend clist ${cname}
}
if {${ja4h_original} == 0 }{
set clist [lsort ${clist}]
}
foreach ck ${clist} {
append cstr "${ck},"
append ckvstr "${ck}=[HTTP::cookie value ${ck}],"
}
set cstr [string trimright ${cstr} ","]
set ckvstr [string trimright ${ckvstr} ","]
if { $c eq "c" } {
binary scan [sha256 ${cstr}] H* chash
binary scan [sha256 ${ckvstr}] H* ckvhash
set trunc_chash [string range $chash 0 11]
set trunc_ckvhash [string range $ckvhash 0 11]
} else {
set trunc_chash "000000000000"
set trunc_ckvhash "000000000000"
}
# Generate JA4H fingerprint string
set ja4h_fp "${me}${v}${c}${r}${hc}${lang}_${trunc_hhash}_${trunc_chash}_${trunc_ckvhash}"
HTTP::header insert "X-JA4H" $ja4h_fp
# If enabled, Generate JA4H_r(o) fingerprint string
if { ${ja4h_raw} } {
set ja4hr_fp "${me}${v}${c}${r}${hc}${lang}_${hstr}_${cstr}_${ckvstr}"
set ja4h_xhdr "X-JA4H_r"
if { ${ja4h_original} } {
set ja4h_xhdr "X-JA4H_ro"
}
HTTP::header insert ${ja4h_xhdr} ${ja4hr_fp}
}
}