Difference between revisions for Users / Eo Ny
|
← Previous edit |
Next edit →
Revision 3 as of
05/05/2026 18:39
▼
6
05/21/2026 16:13
WikiAdmin
5
05/19/2026 11:04
WikiAdmin
4
05/05/2026 18:48
EoNy
3
05/05/2026 18:39
EoNy
(49.6 KiB) +1,577 EoNy |
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*