Difference between revisions for Users / Eo Ny




← Previous edit
Next edit →

Additions:
== Session Management Technical Documentation ==
=== Overview ===
The ##Session## class is an abstract session management system for
WackoWiki that extends ##ArrayObject## to provide secure, configurable
session handling. It implements sophisticated security features
including session ID regeneration, anti-replay protection, nonce
verification, and user agent/IP validation.
**Location:** ##src/class/session.php##  
**Type:** Abstract class (must be extended with a
##SessionStoreInterface## implementation)  
**Inheritance:** ##ArrayObject##
----
=== Table of Contents ===
  1. ((#core-concepts Core Concepts))
  2. ((#architecture Architecture))
  3. ((#configuration Configuration))
  4. ((#usage Usage))
  5. ((#security-features Security Features))
  6. ((#api-reference API Reference))
  7. ((#session-lifecycle Session Lifecycle))
  8. ((#flash-data Flash Data))
  9. ((#nonce-system Nonce System))
  10. ((#cookie-management Cookie Management))
  11. ((#error-handling Error Handling))
  12. ((#implementation-guide Implementation Guide))
----
=== Core Concepts ===
==== Session State ====
  - **Inactive** (##$active = false##): Session not yet started or has
been closed
  - **Active** (##$active = true##): Session is running and can
store/retrieve data
  - **Regenerated**: Session ID has been replaced (tracked via
##$regenerated## flag)
==== Session Data Storage ====
Session data is stored as an array accessible through ##ArrayObject##
interface:
%%php
%%
==== Sticky Data ====
Variables prefixed with ##sticky_## are persistent across session
resets:
  - ##sticky__created##: Session creation timestamp
  - ##sticky__flash##: Flash data lifetime tracking
  - ##sticky__log##: Regeneration event log
  - ##sticky__ip##: IP change tracking
==== Internal Tracking Variables ====
Variables prefixed with ##__## are internal session metadata:
  - ##__started##: Session start time
  - ##__updated##: Last session update time
  - ##__regenerated##: Last session ID regeneration time
  - ##__user_agent##: Client user agent string
  - ##__user_ip##: Client IP address
  - ##__user_tls##: TLS/SSL status
  - ##__nonces##: Active nonce storage
  - ##__expire##: Session expiration time (for old sessions)
----
=== Architecture ===
==== Class Hierarchy ====
%%
%%
==== Key Methods Categories ====
  - ##__construct()##: Initialize session object
  - ##start()##: Begin a session
  - ##write_close()##: Save and close session
  - ##restart()##: Destroy and restart session
  - ##terminator()##: Shutdown handler (garbage collection, flash data
cleanup)
  - ##regenerate_id()##: Replace session ID
  - ##verify_nonce()##: Validate nonce tokens
  - ##prevent_replay()##: Anti-replay protection
  - ##create_nonce()##: Generate nonce tokens
  - ##store_open()##: Open session storage
  - ##store_read()##: Read session data
  - ##store_write()##: Write session data
  - ##store_close()##: Close session storage
  - ##store_gc()##: Garbage collection
  - ##store_validate_id()##: Validate session ID format
  - ##store_generate_id()##: Generate new session ID
  - ##setcookie()##: Set HTTP cookie with security headers
  - ##get_cookie()##: Retrieve cookie value
  - ##set_cookie()##: Set cookie (legacy interface)
  - ##delete_cookie()##: Remove cookie
  - ##send_cookie()##: Internal cookie transmission
----
=== Configuration ===
==== Configuration Properties (Public) ====
All configuration properties are prefixed with ##cf_## (config) and
can be set before calling ##start()##:
===== Session Behavior =====
%%php
%%
===== Nonce & Replay Protection =====
%%php
%%
===== Garbage Collection =====
%%php
%%
===== Cookie Settings =====
%%php
%%
===== Cache Control =====
%%php
%%
===== Security Validation =====
%%php
%%
===== HTTP Context (Set by HTTP class) =====
%%php
%%
----
=== Usage ===
==== Basic Session Setup ====
%%php
%%
==== Session Data Access ====
%%php
%%
==== Session ID Management ====
%%php
%%
==== Session State ====
%%php
%%
----
=== Security Features ===
==== 1. Session ID Regeneration ====
  - Initial session creation (##regenerated = 2##)
  - First request after creation (##regenerated = 1##)
  - Periodic forced regeneration (based on ##cf_regen_time## and
##cf_regen_probability##)
  - Session validation failures
%%php
%%
  - ##$delete_old##: 
  - ##false## (0): Keep old session active for ~5 seconds (for pending
AJAX requests)
  - ##true## (1): Keep old session for time specified (unused in
current code)
  - ##2##: Immediately destroy old session
  - New session ID is generated via ##store_generate_id()##
  - Old session data is copied to new ID
  - Old session marked with ##__expire## timestamp
  - Cookie immediately updated with new ID
  - Single regeneration per request (checked via
##$this->regenerated## flag)
  - Logged in ##sticky__log## for debugging (max 15 entries)
%%php
%%
==== 2. User Agent Validation ====
  - Stores user agent on first request
  - Compares on subsequent requests using ##similar_text()##
  - Destroys session if similarity < 95%
  - Useful against bot attacks or stolen sessions
%%php
%%
==== 3. IP Address Validation ====
  - Stores IP on first request
  - Compares on subsequent requests
  - Soft failure on mismatch: ##destroy = 1## (keeps regenerating)
  - Tracks IP changes in ##sticky__ip##
%%php
%%
%%php
%%
==== 4. TLS/SSL Validation ====
  - Checks if connection transitioned from HTTPS to HTTP
  - Destroys session on mismatch
%%php
%%
==== 5. Anti-Replay Protection ====
  - Generates unique "NoReplay" nonce on each request
  - Cookie-based nonce verification
  - Detects rapid-fire requests (AJAX attacks)
%%php
%%
%%
%%
==== 6. Referer Validation (Optional) ====
%%php
%%
----
=== API Reference ===
==== Public Methods ====
===== Lifecycle Management =====
====== ##start($name = null, $id = null): bool## ======
  - ##$name## (string|null): Session name (cookie name base).
Alphanumeric + underscore/dash. Defaults to 'sesid'
  - ##$id## (string|null): Existing session ID to resume. If null,
attempts to read from cookie
**Returns:** ##true## if session started successfully, ##false## on
error
  - Sets headers (cookies, cache control)
  - Populates session data from storage
  - Performs security validations
  - May trigger session ID regeneration
%%php
%%
  1. Reject if headers already sent
  2. Validate session name format
  3. Retrieve ID from parameter or cookie
  4. Check Referer header (if configured)
  5. Validate ID format via ##store_validate_id()##
  6. Read session data from storage
  7. Verify nonces and timestamps
  8. Check user agent, IP, TLS
  9. Regenerate if needed
----
====== ##write_close(): void## ======
  - Calls ##write_session()## to serialize and store data
  - Calls ##store_close()## to close storage handler
  - Sets ##$active = false##
%%php
%%
----
====== ##restart(): bool## ======
**Equivalent to:** ##regenerate_id(true) + clean_vars() + populate()##
**Returns:** ##true## on success, ##false## on error
  - User logout and new login
  - Security reset
  - Complete session refresh
%%php
%%
----
===== Session Access =====
====== ##id(): mixed## ======
%%php
%%
----
====== ##name(): string## ======
%%php
%%
----
====== ##active(): bool## ======
**Returns:** ##true## if session is started and active, ##false##
otherwise
%%php
%%
----
====== ##message(): string|null## ======
  - ##'replay'##: Replay attack detected
  - ##'obsolete'##: Session marked for expiration
  - ##'reg_expire'##: Regeneration expiration reached
  - ##'max_session'##: Max session lifetime exceeded
  - ##'max_idle'##: Idle timeout exceeded
  - ##'ua'##: User agent mismatch (>5% difference)
  - ##'tls'##: TLS status changed
  - ##'ip'##: IP address mismatch
  - ##'restart'##: Session manually restarted
  - ##null##: No state change
%%php
%%
----
====== ##toArray(): array## ======
**Note:** This is a direct call to ##ArrayObject::getArrayCopy()##
%%php
%%
----
===== Nonce System =====
====== ##create_nonce($action, $expires = null): string## ======
  - ##$action## (string): Action identifier (e.g.,
'form_submit', 'delete_action')
  - ##$expires## (int|null): Expiration time in seconds. Defaults to
##cf_nonce_lifetime##
%%php
%%
  - Stored in ##$session->__nonces[]##
  - Key: ##{action}.{base64_encoded_hash}##
  - Value: Expiration timestamp
----
====== ##verify_nonce($action, $code, $protect = 0)## ======
  - ##$action## (string): Action identifier that was used in
##create_nonce()##
  - ##$code## (string): Nonce token from user
  - ##$protect## (int): Protection level
  - ##0##: Single-use nonce (consumed on first verification)
  - ##1+##: Protected nonce (can verify multiple times, prevents fast
replays)
  - ##true## (1): Nonce verified and valid
  - ##false## (0): Nonce invalid or expired
  - ##-1##: Protected nonce used twice in quick succession (possible
AJAX attack)
%%php
%%
  - Expired nonces automatically removed
  - Verified single-use nonces removed from storage
----
===== Cookie Management =====
====== ##setcookie($name, $value = null, $expires = 0, $path = null,
$domain = null, $secure = null, $httponly = null, $samesite = null):
bool## ======
  - ##$name##: Cookie name (automatically URL-encoded)
  - ##$value##: Cookie value (automatically URL-encoded, null to
delete)
  - ##$expires##: Expiration timestamp (0 = session cookie)
  - ##$path##: Cookie path (default: ##cf_cookie_path##)
  - ##$domain##: Cookie domain (default: ##cf_cookie_domain##)
  - ##$secure##: HTTPS only (default: ##cf_cookie_secure##)
  - ##$httponly##: Disable JS access (default: ##cf_cookie_httponly##)
  - ##$samesite##: SameSite attribute (default:
##cf_cookie_samesite##)
**Returns:** ##true## on success, ##false## if headers already sent
  - RFC 2616 2.2 token encoding for cookie name
  - RFC 6265 4.1.1 cookie-octet encoding for value
  - Removes duplicate cookie headers automatically
  - Adds all security attributes (secure, httponly, samesite)
  - Does NOT replace existing cookies (allows multiple Set-Cookie
headers)
%%php
%%
----
====== ##get_cookie($name)## ======
  - ##$name##: Cookie name (prefix automatically added)
%%php
%%
----
====== ##set_cookie($name, $value, $persistent = false): void## ======
Legacy cookie setter (alternative to ##setcookie()##).
  - ##$name##: Cookie name (prefix added)
  - ##$value##: Cookie value
  - ##$persistent##: 
  - ##false##: Session cookie (deleted on browser close)
  - ##0##: Use ##cf_cookie_persistent## config
%%php
%%
----
====== ##delete_cookie($name): void## ======
  - ##$name##: Cookie name (prefix added)
%%php
%%
----
====== ##unsetcookie($name): void## ======
Alias for ##setcookie($name)## with no value (convenience method).
%%php
%%
----
==== Protected Methods (For Store Implementation) ====
===== ##regenerate_id($delete_old = false, $message = ''):
bool## =====
----
===== ##store_generate_id(): string## =====
**Default Implementation:** Returns 21-character random alphanumeric
string via ##Ut::random_token(21)##
%%php
%%
----
===== ##store_validate_id($id): bool## =====
**Default Implementation:** Regex check: ##/^[a-zA-Z\d]{21}$/##
%%php
%%
----
===== ##store_open($name): void## =====
%%php
%%
----
===== ##store_read($id, $lock = false): string|false## =====
  - ##$id##: Session ID to read
  - ##$lock##: If true, lock the session file for writing (create new)
  - Serialized session data (string) if found and locked
  - Empty string (##''##) if new session should be created
  - ##false## if session doesn't exist or read error
%%php
%%
----
===== ##store_write($id, $data): void## =====
  - ##$id##: Session ID
  - ##$data##: Serialized session data (already processed by
##Ut::serialize()##)
%%php
%%
----
===== ##store_close(): void## =====
%%php
%%
----
===== ##store_gc(): void## =====
  - Shutdown handler (probabilistic, based on ##cf_gc_probability##)
  - Sessions older than ##cf_gc_maxlifetime## seconds
%%php
%%
----
==== Private Methods (Internal Use) ====
====== ##populate(): void## ======
**Called by:** ##start()##, ##restart()##
  - ##__started##: Current timestamp
  - ##__regenerated##: Current timestamp
  - ##__user_agent##: Browser user agent
  - ##__user_ip##: Client IP (if configured)
  - ##__user_tls##: TLS status (if configured)
  - ##sticky__created##: Creation time (if not exists)
----
====== ##write_session(): void## ======
**Called by:** ##regenerate_id()##, ##write_close()##,
##terminator()##
  - ##__updated##: Current timestamp
  - Calls ##store_write()## with serialized data
----
====== ##clean_vars(): void## ======
**Called by:** ##restart()##, session validation failure
**Preserves:** Variables starting with ##sticky_##
----
====== ##prevent_replay(): void## ======
**Called by:** ##populate()##
  - Creates 'NoReplay' nonce
  - Sends in cookie: ##{cf_cookie_prefix}NoReplay##
----
====== ##cache_limiter(): void## ======
**Called by:** ##start()## after session data loaded
  - ##'public'##: Cacheable, ##Cache-Control: public,
max-age=...##
  - ##'private'##: Private, ##Cache-Control: private,
max-age=...##
  - ##'private_no_expire'##: Private no TTL
  - ##'nocache'##: No storage, ##Cache-Control: no-store##
  - ##'none'##: No headers (default)
----
====== ##set_new_id(): void## ======
**Called by:** ##regenerate_id()##, ##start()## (for new sessions)
----
====== ##remove_cookie($cookie): void## ======
**Called by:** ##setcookie()## before setting new value
----
====== ##nonce_index($action, $code): string## (static) ======
**Returns:** ##{action}.{base64_encoded_hash}##
----
----
=== Session Lifecycle ===
==== Complete Session Flow ====
%%
%%
==== First Request (New Session) ====
%%
%%
==== Subsequent Request (Resume Session) ====
%%
%%
==== Session ID Regeneration ====
%%
%%
==== Session Destruction ====
%%
%%
----
=== Flash Data ===
==== Usage ====
%%php
%%
==== How It Works ====
  1. **Storage:** Flash data stored in ##$session->sticky__flash##
  - Key: Variable name
  - Value: Lifetime in requests
  2. **Cleanup:** In ##terminator()## (shutdown handler):
   %%php
   %%
  3. **Persistence:** Flash variables are kept in ##sticky__flash##
even during session resets
==== Example: Login Flow ====
%%php
%%
----
=== Nonce System ===
==== Terminology ====
  - **Nonce:** Number used ONCE - cryptographic token for action
verification
  - **Action:** Type of operation being protected (e.g.,
'form_submit', 'delete_user')
  - **Protected Nonce:** Can be verified multiple times with
protection against rapid reuse
==== Complete Example: Form Protection ====
%%php
%%
==== Example: Protected Nonce (AJAX-Safe) ====
%%php
%%
==== Nonce Storage Format ====
%%
%%
==== Security Properties ====
  - **CSRF Protection:** Nonce must match to process form
  - **One-Time Use:** Each nonce consumed after first verification
(unless protected)
  - **Expiration:** Nonces automatically expire
  - **Action-Specific:** Each action has separate nonce space
  - **AJAX-Safe:** Protected nonces allow multiple quick verifications
----
=== Cookie Management ===
==== Security Features ====
The ##setcookie()## method implements comprehensive cookie security:
===== Encoding =====
%%php
%%
===== Security Attributes =====
%%php
%%
===== No Duplicate Headers =====
%%php
%%
==== Configuration-Driven Defaults ====
%%php
%%
==== Typical Secure Configuration ====
%%php
%%
----
=== Error Handling ===
==== Graceful Degradation ====
===== Headers Already Sent =====
%%php
%%
===== Cookie Setting Failure =====
%%php
%%
===== Storage Errors =====
%%php
%%
==== Debug Logging ====
%%php
%%
To enable: Uncomment lines and ensure ##Ut::dbg()## function exists
==== Event Logging ====
Session events tracked in ##sticky__log##:
%%php
%%
  - Session regeneration (with reason)
  - Limited to 15 most recent events (old entries archived as
'...')
----
=== Implementation Guide ===
==== Creating a Concrete Session Class ====
===== File-Based Storage =====
%%php
%%
===== Database Storage (PDO) =====
%%php
%%
===== Redis Storage =====
%%php
%%
==== Complete Integration Example ====
%%php
%%
==== Configuration Best Practices ====
%%php
%%
==== Testing Tips ====
%%php
%%
----
=== Security Checklist ===
  - [ ] Use HTTPS only in production
  - [ ] Enable ##cf_cookie_secure##
  - [ ] Enable ##cf_cookie_httponly##
  - [ ] Set ##cf_cookie_samesite## to 'Strict' or
'Lax'
  - [ ] Set appropriate ##cf_max_session## timeout
  - [ ] Set appropriate ##cf_max_idle## timeout
  - [ ] Enable ##cf_prevent_replay##
  - [ ] Validate ##cf_ip## if possible
  - [ ] Validate ##cf_tls## on HTTPS sites
  - [ ] Use nonces for all state-changing forms
  - [ ] Implement proper logout (call ##restart()##)
  - [ ] Regenerate on privilege escalation (login)
  - [ ] Monitor ##sticky__ip## for suspicious changes
  - [ ] Review ##sticky__log## for attack patterns
  - [ ] Implement garbage collection (##store_gc##)
  - [ ] Hash session IDs before storing (see TODOs)
  - [ ] Use secure random token generation
----
=== Common Patterns ===
==== Login Flow ====
%%php
%%
==== Logout Flow ====
%%php
%%
==== CSRF-Protected Form ====
%%php
%%
==== Permission Check with Session Regeneration ====
%%php
%%
==== Session Messages/Flash ====
%%php
%%
----
=== Performance Considerations ===
==== Optimization Tips ====
  1. **Minimize Session Writes:**
  - Session data only written during ##write_close()## or regeneration
  - No unnecessary serialization during reads
  2. **Garbage Collection:**
  - Probabilistic GC (based on ##cf_gc_probability##)
  - Only runs on ~2% of requests by default
  - Customize based on your session volume
  3. **Nonce Cleanup:**
  - Expired nonces automatically removed on verification
  - Verified nonces removed from storage
  - No manual cleanup needed
  4. **Session ID Validation:**
  - Regex-based validation is fast
  - No database lookup needed
  5. **Caching Strategy:**
  - Cache expensive lookups between session operations
  - Session data loaded once per request
==== Benchmarks ====
  - Session start: ~1-5ms (file) / ~2-10ms (database)
  - Session write: <1ms (file) / 1-5ms (database)
  - Nonce generation: <1ms
  - Nonce verification: <1ms
----
=== Troubleshooting ===
==== Session Not Starting ====
%%php
%%
==== Cookie Not Setting ====
%%php
%%
==== Session ID Not Regenerating ====
%%php
%%
==== Nonce Verification Failing ====
%%php
%%
==== Session Data Lost ====
%%php
%%
----
=== TODO Items (From Code Comments) ===
  1. **Do not store session ID in filename or DB index - store hash
instead**
  - Improves security by not exposing IDs in storage layer
  - Would require hashing logic in store_* methods
  2. **Log of IP changes and other possible security alerts**
  - Track ##sticky__ip## changes more comprehensively
  - Create security audit trail
  3. **Allocate internal unique session which lives through lifetime
of uber-session**
  - Multi-session management (parent/child sessions)
  - Useful for complex user flows
  4. **Do not delete old sessions, but use them as hijack pointers**
  - Maintain session history for analysis
  - Detect potential session hijacking patterns
  - Implement session relationship tracking
  5. **All SIDs used later than ~5secs of regenerations is hijacks**
  - Detect and block delayed session ID usage
  - Current implementation allows 5-second window
  - Could be more granular
----
=== References ===
==== Security Standards ====
  - RFC 2616: HTTP/1.1 (Cookie syntax)
  - RFC 6265: HTTP State Management Mechanism
  - RFC 6234: US Secure Hash and Message Authentication Code
Algorithms
  - OWASP: Session Management Cheat Sheet
  - OWASP: Cross-Site Request Forgery (CSRF) Prevention
==== Related Code ====
  - ##Ut::serialize()## / ##Ut::unserialize()##: Session data
serialization
  - ##Ut::random_token()##: Cryptographic token generation
  - ##Ut::http_date()##: HTTP date formatting
  - ##Ut::urlencode()##: Cookie-safe encoding
  - ##Ut::is_empty()##: Empty value checking
==== See Also ====
  - ##src/class/http.php##: HTTP request/response handling
  - ##src/class/auth.php##: Authentication (uses Session)
  - Session security best practices in OWASP documentation
----
=== Version History ===
  - **Current**: Abstract session class with security features
  - **Planned**: Implementation of TODO items above
----
  *Documentation generated: 2026-05-05*  
  *For latest updates, see:
https://github.com/Trojer/wackowiki/blob/main/docs/SESSION_DOCUMENTATI
ON.md*

Deletions:
# Session Management Technical Documentation
## Overview
The `Session` class is an abstract session management system for
WackoWiki that extends `ArrayObject` to provide secure, configurable
session handling. It implements sophisticated security features
including session ID regeneration, anti-replay protection, nonce
verification, and user agent/IP validation.
**Location:** `src/class/session.php`  
**Type:** Abstract class (must be extended with a
`SessionStoreInterface` implementation)  
**Inheritance:** `ArrayObject`
---
## Table of Contents
1. [Core Concepts](#core-concepts)
2. [Architecture](#architecture)
3. [Configuration](#configuration)
4. [Usage](#usage)
5. [Security Features](#security-features)
6. [API Reference](#api-reference)
7. [Session Lifecycle](#session-lifecycle)
8. [Flash Data](#flash-data)
9. [Nonce System](#nonce-system)
10. [Cookie Management](#cookie-management)
11. [Error Handling](#error-handling)
12. [Implementation Guide](#implementation-guide)
---
## Core Concepts
### Session State
- **Inactive** (`$active = false`): Session not yet started or has
been closed
- **Active** (`$active = true`): Session is running and can
store/retrieve data
- **Regenerated**: Session ID has been replaced (tracked via
`$regenerated` flag)
### Session Data Storage
Session data is stored as an array accessible through `ArrayObject`
interface:
```php
```
### Sticky Data
Variables prefixed with `sticky_` are persistent across session
resets:
- `sticky__created`: Session creation timestamp
- `sticky__flash`: Flash data lifetime tracking
- `sticky__log`: Regeneration event log
- `sticky__ip`: IP change tracking
### Internal Tracking Variables
Variables prefixed with `__` are internal session metadata:
- `__started`: Session start time
- `__updated`: Last session update time
- `__regenerated`: Last session ID regeneration time
- `__user_agent`: Client user agent string
- `__user_ip`: Client IP address
- `__user_tls`: TLS/SSL status
- `__nonces`: Active nonce storage
- `__expire`: Session expiration time (for old sessions)
---
## Architecture
### Class Hierarchy
```
```
### Key Methods Categories
- `__construct()`: Initialize session object
- `start()`: Begin a session
- `write_close()`: Save and close session
- `restart()`: Destroy and restart session
- `terminator()`: Shutdown handler (garbage collection, flash data
cleanup)
- `regenerate_id()`: Replace session ID
- `verify_nonce()`: Validate nonce tokens
- `prevent_replay()`: Anti-replay protection
- `create_nonce()`: Generate nonce tokens
- `store_open()`: Open session storage
- `store_read()`: Read session data
- `store_write()`: Write session data
- `store_close()`: Close session storage
- `store_gc()`: Garbage collection
- `store_validate_id()`: Validate session ID format
- `store_generate_id()`: Generate new session ID
- `setcookie()`: Set HTTP cookie with security headers
- `get_cookie()`: Retrieve cookie value
- `set_cookie()`: Set cookie (legacy interface)
- `delete_cookie()`: Remove cookie
- `send_cookie()`: Internal cookie transmission
---
## Configuration
### Configuration Properties (Public)
All configuration properties are prefixed with `cf_` (config) and can
be set before calling `start()`:
#### Session Behavior
```php
```
#### Nonce & Replay Protection
```php
```
#### Garbage Collection
```php
```
#### Cookie Settings
```php
```
#### Cache Control
```php
```
#### Security Validation
```php
```
#### HTTP Context (Set by HTTP class)
```php
```
---
## Usage
### Basic Session Setup
```php
```
### Session Data Access
```php
```
### Session ID Management
```php
```
### Session State
```php
```
---
## Security Features
### 1. Session ID Regeneration
- Initial session creation (`regenerated = 2`)
- First request after creation (`regenerated = 1`)
- Periodic forced regeneration (based on `cf_regen_time` and
`cf_regen_probability`)
- Session validation failures
```php
```
- `$delete_old`: 
  - `false` (0): Keep old session active for ~5 seconds (for pending
AJAX requests)
  - `true` (1): Keep old session for time specified (unused in current
code)
  - `2`: Immediately destroy old session
- New session ID is generated via `store_generate_id()`
- Old session data is copied to new ID
- Old session marked with `__expire` timestamp
- Cookie immediately updated with new ID
- Single regeneration per request (checked via `$this->regenerated`
flag)
- Logged in `sticky__log` for debugging (max 15 entries)
```php
```
### 2. User Agent Validation
- Stores user agent on first request
- Compares on subsequent requests using `similar_text()`
- Destroys session if similarity < 95%
- Useful against bot attacks or stolen sessions
```php
```
### 3. IP Address Validation
- Stores IP on first request
- Compares on subsequent requests
- Soft failure on mismatch: `destroy = 1` (keeps regenerating)
- Tracks IP changes in `sticky__ip`
```php
```
```php
```
### 4. TLS/SSL Validation
- Checks if connection transitioned from HTTPS to HTTP
- Destroys session on mismatch
```php
```
### 5. Anti-Replay Protection
- Generates unique "NoReplay" nonce on each request
- Cookie-based nonce verification
- Detects rapid-fire requests (AJAX attacks)
```php
```
```
```
### 6. Referer Validation (Optional)
```php
```
---
## API Reference
### Public Methods
#### Lifecycle Management
##### `start($name = null, $id = null): bool`
- `$name` (string|null): Session name (cookie name base). Alphanumeric
+ underscore/dash. Defaults to 'sesid'
- `$id` (string|null): Existing session ID to resume. If null,
attempts to read from cookie
**Returns:** `true` if session started successfully, `false` on error
- Sets headers (cookies, cache control)
- Populates session data from storage
- Performs security validations
- May trigger session ID regeneration
```php
```
1. Reject if headers already sent
2. Validate session name format
3. Retrieve ID from parameter or cookie
4. Check Referer header (if configured)
5. Validate ID format via `store_validate_id()`
6. Read session data from storage
7. Verify nonces and timestamps
8. Check user agent, IP, TLS
9. Regenerate if needed
---
##### `write_close(): void`
- Calls `write_session()` to serialize and store data
- Calls `store_close()` to close storage handler
- Sets `$active = false`
```php
```
---
##### `restart(): bool`
**Equivalent to:** `regenerate_id(true) + clean_vars() + populate()`
**Returns:** `true` on success, `false` on error
- User logout and new login
- Security reset
- Complete session refresh
```php
```
---
#### Session Access
##### `id(): mixed`
```php
```
---
##### `name(): string`
```php
```
---
##### `active(): bool`
**Returns:** `true` if session is started and active, `false`
otherwise
```php
```
---
##### `message(): string|null`
- `'replay'`: Replay attack detected
- `'obsolete'`: Session marked for expiration
- `'reg_expire'`: Regeneration expiration reached
- `'max_session'`: Max session lifetime exceeded
- `'max_idle'`: Idle timeout exceeded
- `'ua'`: User agent mismatch (>5% difference)
- `'tls'`: TLS status changed
- `'ip'`: IP address mismatch
- `'restart'`: Session manually restarted
- `null`: No state change
```php
```
---
##### `toArray(): array`
**Note:** This is a direct call to `ArrayObject::getArrayCopy()`
```php
```
---
#### Nonce System
##### `create_nonce($action, $expires = null): string`
- `$action` (string): Action identifier (e.g.,
'form_submit', 'delete_action')
- `$expires` (int|null): Expiration time in seconds. Defaults to
`cf_nonce_lifetime`
```php
```
- Stored in `$session->__nonces[]`
- Key: `{action}.{base64_encoded_hash}`
- Value: Expiration timestamp
---
##### `verify_nonce($action, $code, $protect = 0)`
- `$action` (string): Action identifier that was used in
`create_nonce()`
- `$code` (string): Nonce token from user
- `$protect` (int): Protection level
  - `0`: Single-use nonce (consumed on first verification)
  - `1+`: Protected nonce (can verify multiple times, prevents fast
replays)
- `true` (1): Nonce verified and valid
- `false` (0): Nonce invalid or expired
- `-1`: Protected nonce used twice in quick succession (possible AJAX
attack)
```php
```
- Expired nonces automatically removed
- Verified single-use nonces removed from storage
---
#### Cookie Management
##### `setcookie($name, $value = null, $expires = 0, $path = null,
$domain = null, $secure = null, $httponly = null, $samesite = null):
bool`
- `$name`: Cookie name (automatically URL-encoded)
- `$value`: Cookie value (automatically URL-encoded, null to delete)
- `$expires`: Expiration timestamp (0 = session cookie)
- `$path`: Cookie path (default: `cf_cookie_path`)
- `$domain`: Cookie domain (default: `cf_cookie_domain`)
- `$secure`: HTTPS only (default: `cf_cookie_secure`)
- `$httponly`: Disable JS access (default: `cf_cookie_httponly`)
- `$samesite`: SameSite attribute (default: `cf_cookie_samesite`)
**Returns:** `true` on success, `false` if headers already sent
- RFC 2616 2.2 token encoding for cookie name
- RFC 6265 4.1.1 cookie-octet encoding for value
- Removes duplicate cookie headers automatically
- Adds all security attributes (secure, httponly, samesite)
- Does NOT replace existing cookies (allows multiple Set-Cookie
headers)
```php
```
---
##### `get_cookie($name)`
- `$name`: Cookie name (prefix automatically added)
```php
```
---
##### `set_cookie($name, $value, $persistent = false): void`
Legacy cookie setter (alternative to `setcookie()`).
- `$name`: Cookie name (prefix added)
- `$value`: Cookie value
- `$persistent`: 
  - `false`: Session cookie (deleted on browser close)
  - `0`: Use `cf_cookie_persistent` config
```php
```
---
##### `delete_cookie($name): void`
- `$name`: Cookie name (prefix added)
```php
```
---
##### `unsetcookie($name): void`
Alias for `setcookie($name)` with no value (convenience method).
```php
```
---
### Protected Methods (For Store Implementation)
#### `regenerate_id($delete_old = false, $message = ''):
bool`
---
#### `store_generate_id(): string`
**Default Implementation:** Returns 21-character random alphanumeric
string via `Ut::random_token(21)`
```php
```
---
#### `store_validate_id($id): bool`
**Default Implementation:** Regex check: `/^[a-zA-Z\d]{21}$/`
```php
```
---
#### `store_open($name): void`
```php
```
---
#### `store_read($id, $lock = false): string|false`
- `$id`: Session ID to read
- `$lock`: If true, lock the session file for writing (create new)
- Serialized session data (string) if found and locked
- Empty string (`''`) if new session should be created
- `false` if session doesn't exist or read error
```php
```
---
#### `store_write($id, $data): void`
- `$id`: Session ID
- `$data`: Serialized session data (already processed by
`Ut::serialize()`)
```php
```
---
#### `store_close(): void`
```php
```
---
#### `store_gc(): void`
- Shutdown handler (probabilistic, based on `cf_gc_probability`)
- Sessions older than `cf_gc_maxlifetime` seconds
```php
```
---
### Private Methods (Internal Use)
##### `populate(): void`
**Called by:** `start()`, `restart()`
- `__started`: Current timestamp
- `__regenerated`: Current timestamp
- `__user_agent`: Browser user agent
- `__user_ip`: Client IP (if configured)
- `__user_tls`: TLS status (if configured)
- `sticky__created`: Creation time (if not exists)
---
##### `write_session(): void`
**Called by:** `regenerate_id()`, `write_close()`, `terminator()`
- `__updated`: Current timestamp
- Calls `store_write()` with serialized data
---
##### `clean_vars(): void`
**Called by:** `restart()`, session validation failure
**Preserves:** Variables starting with `sticky_`
---
##### `prevent_replay(): void`
**Called by:** `populate()`
- Creates 'NoReplay' nonce
- Sends in cookie: `{cf_cookie_prefix}NoReplay`
---
##### `cache_limiter(): void`
**Called by:** `start()` after session data loaded
- `'public'`: Cacheable, `Cache-Control: public,
max-age=...`
- `'private'`: Private, `Cache-Control: private,
max-age=...`
- `'private_no_expire'`: Private no TTL
- `'nocache'`: No storage, `Cache-Control: no-store`
- `'none'`: No headers (default)
---
##### `set_new_id(): void`
**Called by:** `regenerate_id()`, `start()` (for new sessions)
---
##### `remove_cookie($cookie): void`
**Called by:** `setcookie()` before setting new value
---
##### `nonce_index($action, $code): string` (static)
**Returns:** `{action}.{base64_encoded_hash}`
---
---
## Session Lifecycle
### Complete Session Flow
```
```
### First Request (New Session)
```
```
### Subsequent Request (Resume Session)
```
```
### Session ID Regeneration
```
```
### Session Destruction
```
```
---
## Flash Data
### Usage
```php
```
### How It Works
1. **Storage:** Flash data stored in `$session->sticky__flash`
   - Key: Variable name
   - Value: Lifetime in requests
2. **Cleanup:** In `terminator()` (shutdown handler):
   ```php
   ```
3. **Persistence:** Flash variables are kept in `sticky__flash` even
during session resets
### Example: Login Flow
```php
```
---
## Nonce System
### Terminology
- **Nonce:** Number used ONCE - cryptographic token for action
verification
- **Action:** Type of operation being protected (e.g.,
'form_submit', 'delete_user')
- **Protected Nonce:** Can be verified multiple times with protection
against rapid reuse
### Complete Example: Form Protection
```php
```
### Example: Protected Nonce (AJAX-Safe)
```php
```
### Nonce Storage Format
```
```
### Security Properties
- **CSRF Protection:** Nonce must match to process form
- **One-Time Use:** Each nonce consumed after first verification
(unless protected)
- **Expiration:** Nonces automatically expire
- **Action-Specific:** Each action has separate nonce space
- **AJAX-Safe:** Protected nonces allow multiple quick verifications
---
## Cookie Management
### Security Features
The `setcookie()` method implements comprehensive cookie security:
#### Encoding
```php
```
#### Security Attributes
```php
```
#### No Duplicate Headers
```php
```
### Configuration-Driven Defaults
```php
```
### Typical Secure Configuration
```php
```
---
## Error Handling
### Graceful Degradation
#### Headers Already Sent
```php
```
#### Cookie Setting Failure
```php
```
#### Storage Errors
```php
```
### Debug Logging
```php
```
To enable: Uncomment lines and ensure `Ut::dbg()` function exists
### Event Logging
Session events tracked in `sticky__log`:
```php
```
- Session regeneration (with reason)
- Limited to 15 most recent events (old entries archived as
'...')
---
## Implementation Guide
### Creating a Concrete Session Class
#### File-Based Storage
```php
```
#### Database Storage (PDO)
```php
```
#### Redis Storage
```php
```
### Complete Integration Example
```php
```
### Configuration Best Practices
```php
```
### Testing Tips
```php
```
---
## Security Checklist
- [ ] Use HTTPS only in production
- [ ] Enable `cf_cookie_secure`
- [ ] Enable `cf_cookie_httponly`
- [ ] Set `cf_cookie_samesite` to 'Strict' or
'Lax'
- [ ] Set appropriate `cf_max_session` timeout
- [ ] Set appropriate `cf_max_idle` timeout
- [ ] Enable `cf_prevent_replay`
- [ ] Validate `cf_ip` if possible
- [ ] Validate `cf_tls` on HTTPS sites
- [ ] Use nonces for all state-changing forms
- [ ] Implement proper logout (call `restart()`)
- [ ] Regenerate on privilege escalation (login)
- [ ] Monitor `sticky__ip` for suspicious changes
- [ ] Review `sticky__log` for attack patterns
- [ ] Implement garbage collection (`store_gc`)
- [ ] Hash session IDs before storing (see TODOs)
- [ ] Use secure random token generation
---
## Common Patterns
### Login Flow
```php
```
### Logout Flow
```php
```
### CSRF-Protected Form
```php
```
### Permission Check with Session Regeneration
```php
```
### Session Messages/Flash
```php
```
---
## Performance Considerations
### Optimization Tips
1. **Minimize Session Writes:**
   - Session data only written during `write_close()` or regeneration
   - No unnecessary serialization during reads
2. **Garbage Collection:**
   - Probabilistic GC (based on `cf_gc_probability`)
   - Only runs on ~2% of requests by default
   - Customize based on your session volume
3. **Nonce Cleanup:**
   - Expired nonces automatically removed on verification
   - Verified nonces removed from storage
   - No manual cleanup needed
4. **Session ID Validation:**
   - Regex-based validation is fast
   - No database lookup needed
5. **Caching Strategy:**
   - Cache expensive lookups between session operations
   - Session data loaded once per request
### Benchmarks
- Session start: ~1-5ms (file) / ~2-10ms (database)
- Session write: <1ms (file) / 1-5ms (database)
- Nonce generation: <1ms
- Nonce verification: <1ms
---
## Troubleshooting
### Session Not Starting
```php
```
### Cookie Not Setting
```php
```
### Session ID Not Regenerating
```php
```
### Nonce Verification Failing
```php
```
### Session Data Lost
```php
```
---
## TODO Items (From Code Comments)
1. **Do not store session ID in filename or DB index - store hash
instead**
   - Improves security by not exposing IDs in storage layer
   - Would require hashing logic in store_* methods
2. **Log of IP changes and other possible security alerts**
   - Track `sticky__ip` changes more comprehensively
   - Create security audit trail
3. **Allocate internal unique session which lives through lifetime of
uber-session**
   - Multi-session management (parent/child sessions)
   - Useful for complex user flows
4. **Do not delete old sessions, but use them as hijack pointers**
   - Maintain session history for analysis
   - Detect potential session hijacking patterns
   - Implement session relationship tracking
5. **All SIDs used later than ~5secs of regenerations is hijacks**
   - Detect and block delayed session ID usage
   - Current implementation allows 5-second window
   - Could be more granular
---
## References
### Security Standards
- RFC 2616: HTTP/1.1 (Cookie syntax)
- RFC 6265: HTTP State Management Mechanism
- RFC 6234: US Secure Hash and Message Authentication Code Algorithms
- OWASP: Session Management Cheat Sheet
- OWASP: Cross-Site Request Forgery (CSRF) Prevention
### Related Code
- `Ut::serialize()` / `Ut::unserialize()`: Session data serialization
- `Ut::random_token()`: Cryptographic token generation
- `Ut::http_date()`: HTTP date formatting
- `Ut::urlencode()`: Cookie-safe encoding
- `Ut::is_empty()`: Empty value checking
### See Also
- `src/class/http.php`: HTTP request/response handling
- `src/class/auth.php`: Authentication (uses Session)
- Session security best practices in OWASP documentation
---
## Version History
- **Current**: Abstract session class with security features
- **Planned**: Implementation of TODO items above
---
*Documentation generated: 2026-05-05*  
*For latest updates, see:
https://github.com/Trojer/wackowiki/blob/main/docs/SESSION_DOCUMENTATI
ON.md*