c77_secure_db/EXAMPLES.md

1357 lines
36 KiB
Markdown

# c77_secure_db Examples
This document provides practical examples for using the c77_secure_db extension in real-world scenarios.
## 📝 **About These Examples**
We provide comprehensive examples for:
- **Pure SQL** - Direct PostgreSQL usage
- **Laravel** - Full PHP integration with tested patterns
While c77_secure_db is designed to work with any application framework that connects to PostgreSQL, we focus our testing and examples on SQL and Laravel. The extension's database-level security works with Node.js, Django, Ruby on Rails, and other frameworks, but we haven't extensively tested these integrations and prefer not to provide guidance where our expertise is limited.
**Community contributions for other frameworks are welcome!**
---
## 🗄️ **Pure SQL Examples**
### Basic Setup
```sql
-- Install and verify extension
CREATE EXTENSION c77_secure_db;
SELECT c77_secure_db_run_all_tests();
-- Create application schema
CREATE SCHEMA ecommerce;
SELECT c77_secure_db_manage_secure_schemas('add', 'ecommerce');
-- Create secure tables
CREATE TABLE ecommerce.customers (
id BIGSERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
phone TEXT,
status TEXT DEFAULT 'active',
-- Required security columns
content_hash TEXT,
hash_version INTEGER DEFAULT 1,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
CREATE TABLE ecommerce.orders (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT REFERENCES ecommerce.customers(id),
total_amount DECIMAL(10,2) NOT NULL,
status TEXT DEFAULT 'pending',
order_date TIMESTAMPTZ DEFAULT NOW(),
-- Required security columns
content_hash TEXT,
hash_version INTEGER DEFAULT 1,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
```
### Customer Management Examples
```sql
-- Create new customer
SELECT c77_secure_db_operation(jsonb_build_object(
'schema_name', 'ecommerce',
'table_name', 'customers',
'operation', 'insert',
'data', jsonb_build_object(
'email', 'john.doe@example.com',
'first_name', 'John',
'last_name', 'Doe',
'phone', '+1-555-0123'
)
));
-- Response:
{
"success": true,
"operation": "insert",
"schema_name": "ecommerce",
"table_name": "customers",
"rows_affected": 1,
"content_hash": "a1b2c3d4e5f6789...",
"execution_time_ms": 8,
"operation_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-01-26T15:30:00Z"
}
-- Update customer information
SELECT c77_secure_db_operation(jsonb_build_object(
'schema_name', 'ecommerce',
'table_name', 'customers',
'operation', 'update',
'data', jsonb_build_object(
'id', 1,
'phone', '+1-555-9999',
'status', 'premium'
)
));
-- Soft delete customer (preserves data)
SELECT c77_secure_db_operation(jsonb_build_object(
'schema_name', 'ecommerce',
'table_name', 'customers',
'operation', 'soft_delete',
'data', jsonb_build_object('id', 1)
));
-- Upsert customer (insert if new, update if exists)
SELECT c77_secure_db_operation(jsonb_build_object(
'schema_name', 'ecommerce',
'table_name', 'customers',
'operation', 'upsert',
'data', jsonb_build_object(
'id', 2,
'email', 'jane.smith@example.com',
'first_name', 'Jane',
'last_name', 'Smith',
'phone', '+1-555-0456'
)
));
```
### Order Processing Examples
```sql
-- Create new order
SELECT c77_secure_db_operation(jsonb_build_object(
'schema_name', 'ecommerce',
'table_name', 'orders',
'operation', 'insert',
'data', jsonb_build_object(
'customer_id', 1,
'total_amount', 299.99,
'status', 'confirmed'
)
));
-- Update order status
SELECT c77_secure_db_operation(jsonb_build_object(
'schema_name', 'ecommerce',
'table_name', 'orders',
'operation', 'update',
'data', jsonb_build_object(
'id', 1,
'status', 'shipped'
)
));
-- Cancel order (soft delete)
SELECT c77_secure_db_operation(jsonb_build_object(
'schema_name', 'ecommerce',
'table_name', 'orders',
'operation', 'soft_delete',
'data', jsonb_build_object('id', 1)
));
```
### Data Integrity Verification
```sql
-- Check if a customer record has been tampered with
SELECT c77_secure_db_check_freshness(
'ecommerce',
'customers',
jsonb_build_object(
'id', 1,
'email', 'john.doe@example.com',
'first_name', 'John',
'last_name', 'Doe',
'phone', '+1-555-0123',
'status', 'active'
)
);
-- Response indicates tampering status:
{
"success": true,
"id": "1",
"fresh": true,
"stored_hash": "a1b2c3d4e5f6789...",
"calculated_hash": "a1b2c3d4e5f6789...",
"hash_version": 1,
"timestamp": "2025-01-26T15:30:00Z"
}
-- Verify all customer records at once
SELECT c77_secure_db_verify_content_hashes('ecommerce', 'customers');
-- Fix any hash mismatches found
SELECT c77_secure_db_verify_content_hashes('ecommerce', 'customers', true);
-- Bulk freshness check for multiple records
SELECT c77_secure_db_check_freshness_bulk(
'ecommerce',
'customers',
'[
{"id": 1, "email": "john.doe@example.com", "first_name": "John", "last_name": "Doe"},
{"id": 2, "email": "jane.smith@example.com", "first_name": "Jane", "last_name": "Smith"}
]'::jsonb
);
```
### RBAC Integration Examples
```sql
-- Setup RBAC permissions (requires c77_rbac extension)
SELECT c77_rbac_grant_feature('customer_service', 'secure_db_read');
SELECT c77_rbac_grant_feature('customer_service', 'secure_db_update');
SELECT c77_rbac_grant_feature('order_manager', 'secure_db_insert');
SELECT c77_rbac_grant_feature('order_manager', 'secure_db_update');
SELECT c77_rbac_grant_feature('supervisor', 'secure_db_delete');
-- Assign users to roles
SELECT c77_rbac_assign_subject('emp_001', 'customer_service', 'department', 'support');
SELECT c77_rbac_assign_subject('emp_002', 'order_manager', 'department', 'sales');
-- Set user context and perform RBAC-protected operation
SET "c77_rbac.external_id" TO 'emp_001';
SELECT c77_secure_db_operation(
jsonb_build_object(
'schema_name', 'ecommerce',
'table_name', 'customers',
'operation', 'update',
'data', jsonb_build_object(
'id', 1,
'status', 'vip'
)
),
true, -- check_rbac = true
'secure_db_update', -- required_feature
'department', -- scope_type
'support' -- scope_id
);
-- Response includes RBAC information:
{
"success": true,
"operation": "update",
"rbac_check_performed": true,
"rbac_user_id": "emp_001",
"required_feature": "secure_db_update",
...
}
```
### Advanced Configuration
```sql
-- Exclude frequently updated columns from hash calculation
COMMENT ON COLUMN ecommerce.customers.content_hash IS
'{"exclude_hash_columns": ["last_login", "login_count", "last_activity"]}';
-- Generate operation templates for easier development
SELECT c77_secure_db_get_operation_template('ecommerce', 'customers', 'insert');
SELECT c77_secure_db_get_operation_template('ecommerce', 'orders', 'update');
-- System monitoring
SELECT c77_secure_db_health_check();
-- Performance monitoring
SELECT
operation_type,
count(*) as operation_count,
avg(execution_time_ms) as avg_execution_time,
max(execution_time_ms) as max_execution_time
FROM c77_secure_db_operation_audit
WHERE created_at > now() - interval '1 hour'
GROUP BY operation_type
ORDER BY avg_execution_time DESC;
```
### Maintenance Operations
```sql
-- Daily maintenance
SELECT c77_secure_db_cleanup_expired_tokens();
-- Weekly integrity verification
SELECT c77_secure_db_verify_content_hashes('ecommerce', 'customers');
SELECT c77_secure_db_verify_content_hashes('ecommerce', 'orders');
-- Monthly security audit
SELECT
user_name,
operation_type,
count(*) as operation_count,
min(created_at) as first_operation,
max(created_at) as last_operation
FROM c77_secure_db_operation_audit
WHERE created_at > now() - interval '30 days'
GROUP BY user_name, operation_type
ORDER BY operation_count DESC;
```
---
## 🏗️ **Laravel Integration Examples**
### Service Provider Setup
```php
<?php
// app/Providers/SecureDbServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\SecureDbService;
class SecureDbServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(SecureDbService::class, function ($app) {
return new SecureDbService();
});
}
public function boot()
{
// Register the service provider in config/app.php providers array
}
}
```
### Core Service Class
```php
<?php
// app/Services/SecureDbService.php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Exception;
class SecureDbService
{
protected $schema;
public function __construct()
{
$this->schema = config('database.secure_schema', 'ecommerce');
}
/**
* Execute a secure database operation
*/
public function operation(array $data, bool $checkRbac = false, string $requiredFeature = null): array
{
try {
$result = DB::selectOne(
'SELECT c77_secure_db_operation(?, ?, ?) as result',
[
json_encode($data),
$checkRbac,
$requiredFeature
]
);
$response = json_decode($result->result, true);
if (!$response['success']) {
Log::warning('Secure DB operation failed', [
'operation' => $data,
'error' => $response['error'] ?? 'Unknown error',
'operation_id' => $response['operation_id'] ?? null
]);
throw new Exception($response['error'] ?? 'Secure operation failed');
}
Log::info('Secure DB operation completed', [
'operation_type' => $data['operation'],
'table' => $data['table_name'],
'operation_id' => $response['operation_id'],
'execution_time_ms' => $response['execution_time_ms']
]);
return $response;
} catch (Exception $e) {
Log::error('Secure DB operation exception', [
'operation' => $data,
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* Insert record securely
*/
public function insert(string $table, array $data, bool $checkRbac = true): array
{
return $this->operation([
'schema_name' => $this->schema,
'table_name' => $table,
'operation' => 'insert',
'data' => $data
], $checkRbac, 'secure_db_insert');
}
/**
* Update record securely
*/
public function update(string $table, array $data, bool $checkRbac = true): array
{
if (!isset($data['id'])) {
throw new Exception('Primary key "id" is required for update operations');
}
return $this->operation([
'schema_name' => $this->schema,
'table_name' => $table,
'operation' => 'update',
'data' => $data
], $checkRbac, 'secure_db_update');
}
/**
* Upsert record securely
*/
public function upsert(string $table, array $data, bool $checkRbac = true): array
{
return $this->operation([
'schema_name' => $this->schema,
'table_name' => $table,
'operation' => 'upsert',
'data' => $data
], $checkRbac, 'secure_db_insert');
}
/**
* Soft delete record
*/
public function softDelete(string $table, int $id, bool $checkRbac = true): array
{
return $this->operation([
'schema_name' => $this->schema,
'table_name' => $table,
'operation' => 'soft_delete',
'data' => ['id' => $id]
], $checkRbac, 'secure_db_delete');
}
/**
* Hard delete record (permanent)
*/
public function delete(string $table, int $id, bool $checkRbac = true): array
{
return $this->operation([
'schema_name' => $this->schema,
'table_name' => $table,
'operation' => 'delete',
'data' => ['id' => $id]
], $checkRbac, 'secure_db_delete');
}
/**
* Check if record data is fresh (not tampered)
*/
public function checkFreshness(string $table, array $data): array
{
$result = DB::selectOne(
'SELECT c77_secure_db_check_freshness(?, ?, ?) as result',
[$this->schema, $table, json_encode($data)]
);
return json_decode($result->result, true);
}
/**
* Verify content hashes for entire table
*/
public function verifyHashes(string $table, bool $fixMismatches = false): array
{
$result = DB::selectOne(
'SELECT c77_secure_db_verify_content_hashes(?, ?, ?) as result',
[$this->schema, $table, $fixMismatches]
);
return json_decode($result->result, true);
}
/**
* Get system health status
*/
public function healthCheck(): array
{
$result = DB::selectOne('SELECT c77_secure_db_health_check() as result');
return json_decode($result->result, true);
}
}
```
### Middleware for RBAC Context
```php
<?php
// app/Http/Middleware/SecureDbMiddleware.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
class SecureDbMiddleware
{
/**
* Handle an incoming request and set RBAC user context
*/
public function handle(Request $request, Closure $next)
{
if (Auth::check()) {
try {
// Set RBAC user context for secure database operations
DB::statement('SET "c77_rbac.external_id" TO ?', [Auth::id()]);
Log::debug('RBAC context set', ['user_id' => Auth::id()]);
} catch (Exception $e) {
Log::warning('Failed to set RBAC context', [
'user_id' => Auth::id(),
'error' => $e->getMessage()
]);
}
}
return $next($request);
}
}
```
### Customer Model Example
```php
<?php
// app/Models/Customer.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Services\SecureDbService;
use Exception;
class Customer extends Model
{
protected $table = 'ecommerce.customers';
protected $fillable = [
'email', 'first_name', 'last_name', 'phone', 'status'
];
protected $hidden = [
'content_hash', 'hash_version'
];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
protected $secureDb;
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->secureDb = app(SecureDbService::class);
}
/**
* Create new customer using secure operations
*/
public static function createSecure(array $data): self
{
$secureDb = app(SecureDbService::class);
$result = $secureDb->insert('customers', $data);
// Assuming the operation returns the created record data
$customer = new static();
$customer->exists = true;
$customer->fill($data);
return $customer;
}
/**
* Update customer using secure operations
*/
public function updateSecure(array $data): bool
{
if (!$this->exists) {
throw new Exception('Cannot update non-existent customer');
}
$data['id'] = $this->getKey();
$result = $this->secureDb->update('customers', $data);
// Update model attributes
$this->fill($data);
return $result['success'];
}
/**
* Soft delete customer using secure operations
*/
public function deleteSecure(): bool
{
if (!$this->exists) {
return false;
}
$result = $this->secureDb->softDelete('customers', $this->getKey());
return $result['success'];
}
/**
* Check if customer data is fresh (not tampered)
*/
public function isFresh(): bool
{
if (!$this->exists) {
return false;
}
$result = $this->secureDb->checkFreshness('customers', $this->toArray());
return $result['success'] && $result['fresh'];
}
/**
* Get customer orders
*/
public function orders()
{
return $this->hasMany(Order::class, 'customer_id');
}
}
```
### Order Model Example
```php
<?php
// app/Models/Order.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Services\SecureDbService;
class Order extends Model
{
protected $table = 'ecommerce.orders';
protected $fillable = [
'customer_id', 'total_amount', 'status', 'order_date'
];
protected $hidden = [
'content_hash', 'hash_version'
];
protected $casts = [
'total_amount' => 'decimal:2',
'order_date' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
/**
* Create new order using secure operations
*/
public static function createSecure(array $data): self
{
$secureDb = app(SecureDbService::class);
$result = $secureDb->insert('orders', $data);
$order = new static();
$order->exists = true;
$order->fill($data);
return $order;
}
/**
* Update order status securely
*/
public function updateStatusSecure(string $status): bool
{
$result = app(SecureDbService::class)->update('orders', [
'id' => $this->getKey(),
'status' => $status
]);
if ($result['success']) {
$this->status = $status;
return true;
}
return false;
}
/**
* Cancel order (soft delete)
*/
public function cancelSecure(): bool
{
$result = app(SecureDbService::class)->softDelete('orders', $this->getKey());
return $result['success'];
}
/**
* Get related customer
*/
public function customer()
{
return $this->belongsTo(Customer::class);
}
}
```
### Controller Examples
```php
<?php
// app/Http/Controllers/CustomerController.php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Services\SecureDbService;
use Illuminate\Http\Request;
use Exception;
class CustomerController extends Controller
{
protected $secureDb;
public function __construct(SecureDbService $secureDb)
{
$this->secureDb = $secureDb;
}
/**
* Create new customer
*/
public function store(Request $request)
{
$validated = $request->validate([
'email' => 'required|email|unique:ecommerce.customers,email',
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'phone' => 'nullable|string|max:20',
'status' => 'sometimes|in:active,inactive,premium'
]);
try {
$customer = Customer::createSecure($validated);
return response()->json([
'success' => true,
'message' => 'Customer created successfully',
'customer' => $customer->toArray()
], 201);
} catch (Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 400);
}
}
/**
* Update customer
*/
public function update(Request $request, int $id)
{
$validated = $request->validate([
'email' => 'sometimes|email|unique:ecommerce.customers,email,' . $id,
'first_name' => 'sometimes|string|max:255',
'last_name' => 'sometimes|string|max:255',
'phone' => 'nullable|string|max:20',
'status' => 'sometimes|in:active,inactive,premium'
]);
try {
$customer = Customer::find($id);
if (!$customer) {
return response()->json(['error' => 'Customer not found'], 404);
}
$customer->updateSecure($validated);
return response()->json([
'success' => true,
'message' => 'Customer updated successfully',
'customer' => $customer->fresh()->toArray()
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 400);
}
}
/**
* Delete customer (soft delete)
*/
public function destroy(int $id)
{
try {
$customer = Customer::find($id);
if (!$customer) {
return response()->json(['error' => 'Customer not found'], 404);
}
$customer->deleteSecure();
return response()->json([
'success' => true,
'message' => 'Customer deleted successfully'
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 400);
}
}
/**
* Verify customer data integrity
*/
public function verifyIntegrity(int $id)
{
try {
$customer = Customer::find($id);
if (!$customer) {
return response()->json(['error' => 'Customer not found'], 404);
}
$isFresh = $customer->isFresh();
return response()->json([
'customer_id' => $id,
'is_fresh' => $isFresh,
'message' => $isFresh ? 'Data integrity verified' : 'Data tampering detected!',
'verified_at' => now()
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 500);
}
}
}
```
### Order Controller
```php
<?php
// app/Http/Controllers/OrderController.php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Order;
use App\Models\Customer;
use Illuminate\Http\Request;
use Exception;
class OrderController extends Controller
{
/**
* Create new order
*/
public function store(Request $request)
{
$validated = $request->validate([
'customer_id' => 'required|exists:ecommerce.customers,id',
'total_amount' => 'required|numeric|min:0.01',
'status' => 'sometimes|in:pending,confirmed,shipped,delivered,cancelled'
]);
try {
$order = Order::createSecure($validated);
return response()->json([
'success' => true,
'message' => 'Order created successfully',
'order' => $order->toArray()
], 201);
} catch (Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 400);
}
}
/**
* Update order status
*/
public function updateStatus(Request $request, int $id)
{
$validated = $request->validate([
'status' => 'required|in:pending,confirmed,shipped,delivered,cancelled'
]);
try {
$order = Order::find($id);
if (!$order) {
return response()->json(['error' => 'Order not found'], 404);
}
$order->updateStatusSecure($validated['status']);
return response()->json([
'success' => true,
'message' => 'Order status updated successfully',
'order' => $order->fresh()->toArray()
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 400);
}
}
/**
* Cancel order
*/
public function cancel(int $id)
{
try {
$order = Order::find($id);
if (!$order) {
return response()->json(['error' => 'Order not found'], 404);
}
$order->cancelSecure();
return response()->json([
'success' => true,
'message' => 'Order cancelled successfully'
]);
} catch (Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 400);
}
}
}
```
### Configuration
```php
<?php
// config/database.php
return [
// ... existing database config
'secure_schema' => env('SECURE_DB_SCHEMA', 'ecommerce'),
// ... rest of config
];
```
```env
# .env additions
SECURE_DB_SCHEMA=ecommerce
```
### Artisan Commands for Maintenance
```php
<?php
// app/Console/Commands/SecureDbMaintenance.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\SecureDbService;
class SecureDbMaintenance extends Command
{
protected $signature = 'securedb:maintain {--verify-hashes : Verify content hashes}';
protected $description = 'Run secure database maintenance tasks';
protected $secureDb;
public function __construct(SecureDbService $secureDb)
{
parent::__construct();
$this->secureDb = $secureDb;
}
public function handle()
{
$this->info('Running secure database maintenance...');
// Cleanup expired tokens
$this->info('Cleaning up expired tokens...');
$cleanedTokens = DB::selectOne('SELECT c77_secure_db_cleanup_expired_tokens() as count');
$this->info("Cleaned up {$cleanedTokens->count} expired tokens");
// Health check
$health = $this->secureDb->healthCheck();
$this->info("System health: {$health['extension_version']}");
$this->info("Error rate (1h): {$health['error_rate_1h']}%");
// Optional hash verification
if ($this->option('verify-hashes')) {
$this->info('Verifying content hashes...');
$customerResults = $this->secureDb->verifyHashes('customers');
$this->info("Customers: {$customerResults['total_records']} records, {$customerResults['mismatch_count']} mismatches");
$orderResults = $this->secureDb->verifyHashes('orders');
$this->info("Orders: {$orderResults['total_records']} records, {$orderResults['mismatch_count']} mismatches");
}
$this->info('Maintenance completed successfully!');
}
}
```
### Task Scheduling
```php
<?php
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
// Daily secure database maintenance
$schedule->command('securedb:maintain')
->daily()
->at('02:00')
->appendOutputTo(storage_path('logs/securedb-maintenance.log'));
// Weekly hash verification
$schedule->command('securedb:maintain --verify-hashes')
->weekly()
->at('03:00')
->appendOutputTo(storage_path('logs/securedb-verification.log'));
// Monitor system health every 15 minutes
$schedule->call(function () {
$secureDb = app(SecureDbService::class);
$health = $secureDb->healthCheck();
// Alert if error rate is high
if ($health['error_rate_1h'] > 5) {
Log::critical('High error rate detected in secure database', $health);
// Send notification to administrators
}
// Alert if too many active tokens
if ($health['active_tokens'] > 100) {
Log::warning('High number of active tokens detected', $health);
}
})->everyFifteenMinutes();
}
```
### Event Listeners for Audit Logging
```php
<?php
// app/Listeners/SecureDbAuditLogger.php
namespace App\Listeners;
use Illuminate\Support\Facades\Log;
use App\Services\SecureDbService;
class SecureDbAuditLogger
{
protected $secureDb;
public function __construct(SecureDbService $secureDb)
{
$this->secureDb = $secureDb;
}
/**
* Log important business events with integrity verification
*/
public function handle($event)
{
// Example: Log when important customer changes occur
if ($event instanceof CustomerUpdated) {
$freshness = $this->secureDb->checkFreshness('customers', $event->customer->toArray());
if (!$freshness['fresh']) {
Log::critical('Customer data tampering detected!', [
'customer_id' => $event->customer->id,
'expected_hash' => $freshness['calculated_hash'],
'stored_hash' => $freshness['stored_hash']
]);
}
}
}
}
```
### Testing Examples
```php
<?php
// tests/Feature/SecureDbTest.php
namespace Tests\Feature;
use Tests\TestCase;
use App\Services\SecureDbService;
use App\Models\Customer;
use Illuminate\Foundation\Testing\RefreshDatabase;
class SecureDbTest extends TestCase
{
use RefreshDatabase;
protected $secureDb;
protected function setUp(): void
{
parent::setUp();
$this->secureDb = app(SecureDbService::class);
}
/** @test */
public function it_can_create_customer_securely()
{
$customerData = [
'email' => 'test@example.com',
'first_name' => 'Test',
'last_name' => 'User',
'phone' => '+1-555-0123'
];
$result = $this->secureDb->insert('customers', $customerData, false);
$this->assertTrue($result['success']);
$this->assertEquals('insert', $result['operation']);
$this->assertNotEmpty($result['content_hash']);
$this->assertNotEmpty($result['operation_id']);
}
/** @test */
public function it_can_update_customer_securely()
{
// Create customer first
$customer = Customer::createSecure([
'email' => 'test@example.com',
'first_name' => 'Test',
'last_name' => 'User'
]);
// Update customer
$updateData = [
'id' => 1, // Assuming first customer
'first_name' => 'Updated',
'last_name' => 'Name'
];
$result = $this->secureDb->update('customers', $updateData, false);
$this->assertTrue($result['success']);
$this->assertEquals('update', $result['operation']);
$this->assertEquals(1, $result['rows_affected']);
}
/** @test */
public function it_can_verify_data_freshness()
{
// Create customer
$customerData = [
'email' => 'fresh@example.com',
'first_name' => 'Fresh',
'last_name' => 'Data'
];
$this->secureDb->insert('customers', $customerData, false);
// Verify freshness
$freshness = $this->secureDb->checkFreshness('customers', array_merge($customerData, ['id' => 1]));
$this->assertTrue($freshness['success']);
$this->assertTrue($freshness['fresh']);
$this->assertNotEmpty($freshness['stored_hash']);
$this->assertEquals($freshness['stored_hash'], $freshness['calculated_hash']);
}
/** @test */
public function it_prevents_direct_database_modifications()
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Direct modifications not allowed');
// This should fail because we're bypassing the secure operation
DB::insert('INSERT INTO ecommerce.customers (email, first_name, last_name) VALUES (?, ?, ?)', [
'direct@example.com',
'Direct',
'Insert'
]);
}
/** @test */
public function it_can_run_system_health_check()
{
$health = $this->secureDb->healthCheck();
$this->assertTrue($health['success']);
$this->assertEquals('2.0', $health['extension_version']);
$this->assertIsNumeric($health['secure_schemas_count']);
$this->assertIsNumeric($health['active_tokens']);
}
/** @test */
public function it_can_verify_table_hashes()
{
// Create some test data
$this->secureDb->insert('customers', [
'email' => 'hash1@example.com',
'first_name' => 'Hash',
'last_name' => 'Test1'
], false);
$this->secureDb->insert('customers', [
'email' => 'hash2@example.com',
'first_name' => 'Hash',
'last_name' => 'Test2'
], false);
// Verify all hashes
$verification = $this->secureDb->verifyHashes('customers');
$this->assertTrue($verification['success']);
$this->assertEquals(2, $verification['total_records']);
$this->assertEquals(0, $verification['mismatch_count']);
}
}
```
### API Routes
```php
<?php
// routes/api.php
use App\Http\Controllers\CustomerController;
use App\Http\Controllers\OrderController;
Route::middleware(['auth:sanctum', 'securedb'])->group(function () {
// Customer routes
Route::prefix('customers')->group(function () {
Route::post('/', [CustomerController::class, 'store']);
Route::put('/{id}', [CustomerController::class, 'update']);
Route::delete('/{id}', [CustomerController::class, 'destroy']);
Route::post('/{id}/verify', [CustomerController::class, 'verifyIntegrity']);
});
// Order routes
Route::prefix('orders')->group(function () {
Route::post('/', [OrderController::class, 'store']);
Route::put('/{id}/status', [OrderController::class, 'updateStatus']);
Route::delete('/{id}', [OrderController::class, 'cancel']);
});
});
// Register middleware
// In app/Http/Kernel.php:
protected $routeMiddleware = [
// ... existing middleware
'securedb' => \App\Http\Middleware\SecureDbMiddleware::class,
];
```
---
## 🎯 **Best Practices Summary**
### **SQL Best Practices**
1. ✅ Always use `c77_secure_db_operation()` for data modifications
2. ✅ Include required security columns in table definitions
3. ✅ Run regular integrity checks with `c77_secure_db_verify_content_hashes()`
4. ✅ Monitor system health with `c77_secure_db_health_check()`
5. ✅ Use RBAC integration for permission-based access control
### **Laravel Best Practices**
1. ✅ Create dedicated service classes for secure database operations
2. ✅ Use middleware to set RBAC user context automatically
3. ✅ Implement proper error handling and logging
4. ✅ Override model methods to use secure operations
5. ✅ Schedule regular maintenance tasks
6. ✅ Write comprehensive tests for secure operations
### **Security Best Practices**
1. ✅ Never bypass the secure operation functions
2. ✅ Always validate input data before secure operations
3. ✅ Monitor audit logs for suspicious activity
4. ✅ Implement proper RBAC permissions
5. ✅ Regular integrity verification of critical data
6. ✅ Alert on high error rates or token buildup
---
## 🔗 **Framework Compatibility**
While these examples focus on SQL and Laravel, c77_secure_db is designed to work with any framework that connects to PostgreSQL:
- **✅ Tested & Documented**: Pure SQL, Laravel
- **🔧 Community Contributions Welcome**: Node.js, Django, Ruby on Rails, .NET, Java, Python, Go, etc.
The extension's security operates at the database level, making it framework-agnostic. However, we focus our testing and documentation efforts where we have the most expertise to ensure reliability and accuracy.
**Want to contribute examples for other frameworks?** We'd love to see community contributions that expand our examples to other popular frameworks!