PhoenixKit.Utils.SessionFingerprint (phoenix_kit v1.7.43)

Copy Markdown View Source

Session fingerprinting utilities for preventing session hijacking.

This module provides functions to create and verify session fingerprints based on IP address and user agent data. These fingerprints help detect when a session token is being used from a different location or device than where it was created.

Security Considerations

  • IP addresses can change (mobile users, VPNs, etc.), so strict enforcement may impact legitimate users
  • User agents can be spoofed, but provide an additional layer of verification
  • This is defense-in-depth: fingerprinting complements, not replaces, other security measures

Configuration

You can configure the strictness level in your application config:

config :phoenix_kit,
  session_fingerprint_enabled: true,
  session_fingerprint_strict: false  # true = force re-auth, false = log warnings

Examples

# Create a fingerprint from a connection
fingerprint = SessionFingerprint.create_fingerprint(conn)

# Verify a fingerprint
case SessionFingerprint.verify_fingerprint(conn, stored_ip, stored_ua_hash) do
  :ok -> # Fingerprint matches
  {:warning, :ip_mismatch} -> # IP changed, but might be legitimate
  {:warning, :user_agent_mismatch} -> # User agent changed
  {:error, :fingerprint_mismatch} -> # Both changed, likely hijacked
end

Summary

Functions

Creates a session fingerprint from a Plug.Conn connection.

Checks if session fingerprinting is enabled in the application config.

Extracts the IP address from a connection.

Extracts and hashes the user agent from a connection.

Checks if strict fingerprint verification is enabled.

Verifies a session fingerprint against the current connection.

Types

t()

@type t() :: %PhoenixKit.Utils.SessionFingerprint{
  ip_address: String.t(),
  user_agent_hash: String.t()
}

Functions

create_fingerprint(conn)

Creates a session fingerprint from a Plug.Conn connection.

Returns a %SessionFingerprint{} struct with :ip_address and :user_agent_hash fields.

Examples

iex> create_fingerprint(conn)
%SessionFingerprint{ip_address: "192.168.1.1", user_agent_hash: "a1b2c3d4..."}

fingerprinting_enabled?()

Checks if session fingerprinting is enabled in the application config.

Examples

iex> fingerprinting_enabled?()
true

get_ip_address(conn)

Extracts the IP address from a connection.

Handles proxied connections by checking X-Forwarded-For and X-Real-IP headers, falling back to the direct connection IP.

Examples

iex> get_ip_address(conn)
"192.168.1.1"

hash_user_agent(conn)

Extracts and hashes the user agent from a connection.

Returns a SHA256 hash of the user agent string for privacy and storage efficiency.

Examples

iex> hash_user_agent(conn)
"a1b2c3d4e5f6..."

strict_mode?()

Checks if strict fingerprint verification is enabled.

When strict mode is enabled, fingerprint mismatches will force re-authentication. When disabled, mismatches only log warnings.

Examples

iex> strict_mode?()
false

verify_fingerprint(conn, stored_ip, stored_ua_hash)

Verifies a session fingerprint against the current connection.

Returns:

  • :ok if fingerprint matches
  • {:warning, :ip_mismatch} if only IP changed
  • {:warning, :user_agent_mismatch} if only user agent changed
  • {:error, :fingerprint_mismatch} if both changed
  • :ok if stored fingerprint is nil (backward compatibility)

Examples

iex> verify_fingerprint(conn, "192.168.1.1", "abc123")
:ok

iex> verify_fingerprint(conn, "10.0.0.1", "abc123")
{:warning, :ip_mismatch}