fix setting ja4

Signed-off-by: Ronni Skansing <rskansing@gmail.com>
This commit is contained in:
Ronni Skansing
2025-11-05 20:20:40 +01:00
parent 74a681b275
commit ff5921ec02
2 changed files with 32 additions and 19 deletions

View File

@@ -336,8 +336,20 @@ func (s *Server) checkAndServeSharedAsset(c *gin.Context) bool {
// checks if the request should be redirected
// checks if the request is for a static page or static not found page
func (s *Server) Handler(c *gin.Context) {
// inject ja4 fingerprint if available
s.ja4Middleware.GinHandler()(c)
if cacheEntry, ok := s.ja4Middleware.ConnectionFingerprints.Load(c.Request.RemoteAddr); ok {
if entry, ok := cacheEntry.(*middleware.FingerprintEntry); ok {
fingerprint := entry.Fingerprint
entry.LastAccess = time.Now()
c.Request.Header.Set(middleware.HeaderJA4, fingerprint)
c.Set(middleware.ContextKeyJA4, fingerprint)
s.logger.Debugw("ja4 fingerprint injected",
"fingerprint", fingerprint,
"remoteAddr", c.Request.RemoteAddr,
"path", c.Request.URL.Path,
"host", c.Request.Host,
)
}
}
// add error recovery for handler
defer func() {

View File

@@ -20,14 +20,15 @@ const (
ContextKeyJA4 = "ja4_fingerprint"
)
type fingerprintEntry struct {
fingerprint string
lastAccess time.Time
// FingerprintEntry stores a ja4 fingerprint with timestamp
type FingerprintEntry struct {
Fingerprint string
LastAccess time.Time
}
// JA4Middleware handles ja4+ fingerprinting for tls connections
type JA4Middleware struct {
connectionFingerprints sync.Map
ConnectionFingerprints sync.Map
logger *zap.SugaredLogger
}
@@ -54,10 +55,10 @@ func (m *JA4Middleware) periodicCleanup() {
staleThreshold := 10 * time.Minute
count := 0
m.connectionFingerprints.Range(func(key, value interface{}) bool {
if entry, ok := value.(*fingerprintEntry); ok {
if now.Sub(entry.lastAccess) > staleThreshold {
m.connectionFingerprints.Delete(key)
m.ConnectionFingerprints.Range(func(key, value interface{}) bool {
if entry, ok := value.(*FingerprintEntry); ok {
if now.Sub(entry.LastAccess) > staleThreshold {
m.ConnectionFingerprints.Delete(key)
count++
}
}
@@ -70,11 +71,11 @@ func (m *JA4Middleware) periodicCleanup() {
// StoreFingerprintFromClientHello stores the ja4 fingerprint from tls clienthello
func (m *JA4Middleware) StoreFingerprintFromClientHello(hello *tls.ClientHelloInfo) {
fingerprint := ja4plus.JA4(hello)
entry := &fingerprintEntry{
fingerprint: fingerprint,
lastAccess: time.Now(),
entry := &FingerprintEntry{
Fingerprint: fingerprint,
LastAccess: time.Now(),
}
m.connectionFingerprints.Store(hello.Conn.RemoteAddr().String(), entry)
m.ConnectionFingerprints.Store(hello.Conn.RemoteAddr().String(), entry)
}
// ConnStateCallback cleans up fingerprint cache when connection closes
@@ -82,7 +83,7 @@ func (m *JA4Middleware) ConnStateCallback(conn net.Conn, state http.ConnState) {
switch state {
case http.StateClosed, http.StateHijacked:
addr := conn.RemoteAddr().String()
m.connectionFingerprints.Delete(addr)
m.ConnectionFingerprints.Delete(addr)
}
}
@@ -90,12 +91,12 @@ func (m *JA4Middleware) ConnStateCallback(conn net.Conn, state http.ConnState) {
func (m *JA4Middleware) GinHandler() gin.HandlerFunc {
return func(c *gin.Context) {
// try to get fingerprint from cache
if cacheEntry, ok := m.connectionFingerprints.Load(c.Request.RemoteAddr); ok {
if entry, ok := cacheEntry.(*fingerprintEntry); ok {
fingerprint := entry.fingerprint
if cacheEntry, ok := m.ConnectionFingerprints.Load(c.Request.RemoteAddr); ok {
if entry, ok := cacheEntry.(*FingerprintEntry); ok {
fingerprint := entry.Fingerprint
// update last access time
entry.lastAccess = time.Now()
entry.LastAccess = time.Now()
// set as internal header for downstream use
c.Request.Header.Set(HeaderJA4, fingerprint)