Initial commit of c77_secure_db PostgreSQL extension
This commit is contained in:
commit
bcf23f98ad
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
*.a
|
||||||
|
*.pc
|
||||||
|
.DS_Store
|
198
INSTALLATION.md
Normal file
198
INSTALLATION.md
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
# Installation Guide for c77_secure_db
|
||||||
|
|
||||||
|
This guide provides detailed instructions for installing and configuring the `c77_secure_db` PostgreSQL extension.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- PostgreSQL 11 or higher
|
||||||
|
- Database superuser access (for installation)
|
||||||
|
- pgcrypto extension
|
||||||
|
|
||||||
|
## Standard Installation (using PGXS)
|
||||||
|
|
||||||
|
### Step 1: Obtain the Extension
|
||||||
|
|
||||||
|
Either download the extension from the repository or create the files manually:
|
||||||
|
|
||||||
|
1. `c77_secure_db.control` - Extension control file
|
||||||
|
2. `c77_secure_db--1.0.0.sql` - SQL for extension version 1.0.0
|
||||||
|
3. `Makefile` - For installation with PGXS
|
||||||
|
|
||||||
|
### Step 2: Build and Install
|
||||||
|
|
||||||
|
Use the PostgreSQL build infrastructure (PGXS) to build and install the extension:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
This will copy the files to the appropriate PostgreSQL extension directories.
|
||||||
|
|
||||||
|
### Step 3: Create the Extension in Your Database
|
||||||
|
|
||||||
|
Connect to your database and create the extension:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- First, ensure pgcrypto is installed
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
|
||||||
|
-- Then create the c77_secure_db extension
|
||||||
|
CREATE EXTENSION c77_secure_db;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Installation
|
||||||
|
|
||||||
|
If you don't have development tools or prefer a manual installation:
|
||||||
|
|
||||||
|
### Step 1: Locate PostgreSQL Extension Directory
|
||||||
|
|
||||||
|
Find your PostgreSQL extension directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pg_config --sharedir
|
||||||
|
```
|
||||||
|
|
||||||
|
The extension directory is usually `[pg_sharedir]/extension/`.
|
||||||
|
|
||||||
|
### Step 2: Copy Files
|
||||||
|
|
||||||
|
Copy the extension files:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Replace [pg_sharedir] with the output from pg_config --sharedir
|
||||||
|
cp c77_secure_db.control [pg_sharedir]/extension/
|
||||||
|
cp c77_secure_db--1.0.0.sql [pg_sharedir]/extension/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Create the Extension
|
||||||
|
|
||||||
|
Connect to your database and create the extension:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- First, ensure pgcrypto is installed
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
|
||||||
|
-- Then create the c77_secure_db extension
|
||||||
|
CREATE EXTENSION c77_secure_db;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Post-Installation Configuration
|
||||||
|
|
||||||
|
### Step 1: Create a Secure Schema
|
||||||
|
|
||||||
|
Create a schema for your secure tables:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE SCHEMA secure_data;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Register the Schema
|
||||||
|
|
||||||
|
Register the schema with the secure database system:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT c77_manage_secure_schemas('add', 'secure_data');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Verify the Installation
|
||||||
|
|
||||||
|
Verify that the functions are installed correctly:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT pg_proc.proname
|
||||||
|
FROM pg_proc
|
||||||
|
JOIN pg_namespace ON pg_proc.pronamespace = pg_namespace.oid
|
||||||
|
WHERE pg_namespace.nspname = 'public'
|
||||||
|
AND pg_proc.proname LIKE 'c77_%';
|
||||||
|
```
|
||||||
|
|
||||||
|
This should return a list of all the `c77_` functions.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Create a test table and verify that direct modifications are blocked:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Create a test table
|
||||||
|
CREATE TABLE secure_data.test_table (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
content_hash TEXT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
deleted_at TIMESTAMPTZ DEFAULT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Attempt a direct insertion (this should fail)
|
||||||
|
INSERT INTO secure_data.test_table (name) VALUES ('Test');
|
||||||
|
|
||||||
|
-- Use the secure operation function (this should succeed)
|
||||||
|
SELECT c77_secure_db_operation(
|
||||||
|
jsonb_build_object(
|
||||||
|
'schema_name', 'secure_data',
|
||||||
|
'table_name', 'test_table',
|
||||||
|
'operation', 'insert',
|
||||||
|
'data', jsonb_build_object(
|
||||||
|
'name', 'Secure Test'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Verify the record was inserted with content_hash
|
||||||
|
SELECT * FROM secure_data.test_table;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Extension files not found**
|
||||||
|
|
||||||
|
If you see an error like "could not open extension control file", ensure the `.control` file is in the correct location.
|
||||||
|
|
||||||
|
Solution: Verify the location with `pg_config --sharedir` and check that the file is in the `extension` subdirectory.
|
||||||
|
|
||||||
|
2. **pgcrypto not installed**
|
||||||
|
|
||||||
|
The extension requires pgcrypto to be installed first.
|
||||||
|
|
||||||
|
Solution: Run `CREATE EXTENSION pgcrypto;` before trying to create the c77_secure_db extension.
|
||||||
|
|
||||||
|
3. **Permission denied for schema public**
|
||||||
|
|
||||||
|
If you get a permission error when creating the extension, you may not have sufficient privileges.
|
||||||
|
|
||||||
|
Solution: Connect as a database superuser to create the extension.
|
||||||
|
|
||||||
|
4. **Event trigger creation fails**
|
||||||
|
|
||||||
|
If the event trigger fails to create, it might already exist or you might not have permission.
|
||||||
|
|
||||||
|
Solution: Check if the trigger exists with `SELECT * FROM pg_event_trigger;` and drop it if needed.
|
||||||
|
|
||||||
|
### Getting Help
|
||||||
|
|
||||||
|
If you encounter issues not covered in this guide, please:
|
||||||
|
|
||||||
|
1. Check the PostgreSQL logs for detailed error messages
|
||||||
|
2. Verify that all prerequisite steps have been completed
|
||||||
|
3. Contact the extension maintainer for support
|
||||||
|
|
||||||
|
## Upgrading
|
||||||
|
|
||||||
|
To upgrade the extension in the future:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ALTER EXTENSION c77_secure_db UPDATE;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstalling
|
||||||
|
|
||||||
|
If needed, you can remove the extension:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DROP EXTENSION c77_secure_db CASCADE;
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: This will not drop any secured tables, but the security triggers will be removed.
|
6
Makefile
Normal file
6
Makefile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
EXTENSION = c77_secure_db
|
||||||
|
DATA = c77_secure_db--1.0.0.sql
|
||||||
|
|
||||||
|
PG_CONFIG = $(shell which pg_config)
|
||||||
|
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||||
|
include $(PGXS)
|
218
README.md
Normal file
218
README.md
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
# c77_secure_db
|
||||||
|
|
||||||
|
PostgreSQL extension for secure database operations with tamper detection and transaction control.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `c77_secure_db` extension provides a comprehensive set of functions to ensure data integrity and prevent unauthorized modification of data in PostgreSQL tables. It implements content hashing to detect tampering and enforces all modifications to go through a secure function rather than direct SQL commands.
|
||||||
|
|
||||||
|
Key features:
|
||||||
|
- Prevents direct table modifications (INSERT, UPDATE, DELETE) through triggers
|
||||||
|
- Calculates and verifies content hashes to detect data tampering
|
||||||
|
- Automatically manages timestamps (created_at, updated_at, deleted_at)
|
||||||
|
- Provides soft delete functionality
|
||||||
|
- Supports verification of data integrity across entire tables
|
||||||
|
- Handles batch operations efficiently
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- PostgreSQL 11 or higher
|
||||||
|
- pgcrypto extension
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### From Source
|
||||||
|
|
||||||
|
1. Clone the repository:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yourusername/c77_secure_db.git
|
||||||
|
cd c77_secure_db
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Build and install the extension:
|
||||||
|
```bash
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Create the extension in your database:
|
||||||
|
```sql
|
||||||
|
CREATE EXTENSION pgcrypto; -- required dependency
|
||||||
|
CREATE EXTENSION c77_secure_db;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Installation
|
||||||
|
|
||||||
|
If you don't want to use `make`, you can manually install the extension:
|
||||||
|
|
||||||
|
1. Copy `c77_secure_db.control` to your PostgreSQL shared extension directory:
|
||||||
|
```bash
|
||||||
|
cp c77_secure_db.control $(pg_config --sharedir)/extension/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Copy the SQL file to your PostgreSQL extension directory:
|
||||||
|
```bash
|
||||||
|
cp c77_secure_db--1.0.0.sql $(pg_config --sharedir)/extension/
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Create the extension in your database:
|
||||||
|
```sql
|
||||||
|
CREATE EXTENSION pgcrypto; -- required dependency
|
||||||
|
CREATE EXTENSION c77_secure_db;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Setting Up a Secure Schema
|
||||||
|
|
||||||
|
1. Create a schema for your secure tables:
|
||||||
|
```sql
|
||||||
|
CREATE SCHEMA secure_data;
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Register the schema with the secure database system:
|
||||||
|
```sql
|
||||||
|
SELECT c77_manage_secure_schemas('add', 'secure_data');
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Apply triggers to existing tables in the schema:
|
||||||
|
```sql
|
||||||
|
SELECT c77_apply_prevent_triggers('secure_data');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating Secure Tables
|
||||||
|
|
||||||
|
When creating tables in your secure schema, include the required columns for security and auditing:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE secure_data.sensitive_data (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
content_hash TEXT,
|
||||||
|
hash_version INTEGER DEFAULT 1,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
deleted_at TIMESTAMPTZ DEFAULT NULL
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The triggers will be automatically applied to new tables in registered schemas.
|
||||||
|
|
||||||
|
### Performing Secure Operations
|
||||||
|
|
||||||
|
Instead of using direct SQL commands, use the `c77_secure_db_operation` function:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Insert
|
||||||
|
SELECT c77_secure_db_operation(
|
||||||
|
jsonb_build_object(
|
||||||
|
'schema_name', 'secure_data',
|
||||||
|
'table_name', 'sensitive_data',
|
||||||
|
'operation', 'insert',
|
||||||
|
'data', jsonb_build_object(
|
||||||
|
'name', 'Example Entry',
|
||||||
|
'description', 'This is a test'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Update
|
||||||
|
SELECT c77_secure_db_operation(
|
||||||
|
jsonb_build_object(
|
||||||
|
'schema_name', 'secure_data',
|
||||||
|
'table_name', 'sensitive_data',
|
||||||
|
'operation', 'update',
|
||||||
|
'primary_key', 'id',
|
||||||
|
'data', jsonb_build_object(
|
||||||
|
'id', 1,
|
||||||
|
'name', 'Updated Example',
|
||||||
|
'description', 'This has been updated'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Delete (soft delete if deleted_at column exists)
|
||||||
|
SELECT c77_secure_db_operation(
|
||||||
|
jsonb_build_object(
|
||||||
|
'schema_name', 'secure_data',
|
||||||
|
'table_name', 'sensitive_data',
|
||||||
|
'operation', 'delete',
|
||||||
|
'primary_key', 'id',
|
||||||
|
'data', jsonb_build_object(
|
||||||
|
'id', 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generating Operation Templates
|
||||||
|
|
||||||
|
You can generate operation templates for any table:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT c77_get_operation_template('secure_data', 'sensitive_data', 'insert');
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate a complete SQL template that you can copy and modify.
|
||||||
|
|
||||||
|
### Verifying Data Integrity
|
||||||
|
|
||||||
|
To check if a record has been tampered with:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT c77_check_freshness(
|
||||||
|
'secure_data',
|
||||||
|
'sensitive_data',
|
||||||
|
jsonb_build_object('id', 1, 'name', 'Example Entry', 'description', 'This is a test')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
To verify content hashes for all records in a table:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT c77_verify_content_hashes('secure_data', 'sensitive_data');
|
||||||
|
```
|
||||||
|
|
||||||
|
To fix any hash mismatches:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT c77_verify_content_hashes('secure_data', 'sensitive_data', true);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Function Reference
|
||||||
|
|
||||||
|
### Main Functions
|
||||||
|
|
||||||
|
- `c77_secure_db_operation(jsonb)`: Securely performs database operations
|
||||||
|
- `c77_verify_content_hashes(text, text, boolean, integer)`: Verifies content hashes for all records in a table
|
||||||
|
- `c77_check_freshness(text, text, jsonb)`: Verifies if a record has been modified
|
||||||
|
- `c77_calculate_content_hash(text, text, jsonb)`: Calculates a content hash for a record
|
||||||
|
- `c77_get_operation_template(text, text, text)`: Generates a template for secure operations
|
||||||
|
- `c77_manage_secure_schemas(text, text)`: Manages secure schemas
|
||||||
|
|
||||||
|
### Support Functions
|
||||||
|
|
||||||
|
- `c77_prevent_direct_modification()`: Trigger function to prevent direct modifications
|
||||||
|
- `c77_apply_prevent_triggers(text)`: Applies prevention triggers to all tables in a schema
|
||||||
|
- `c77_auto_apply_prevent_triggers()`: Event trigger function for automatically applying triggers
|
||||||
|
|
||||||
|
## Integration with Application Frameworks
|
||||||
|
|
||||||
|
### Laravel Integration
|
||||||
|
|
||||||
|
This extension can be paired with a Laravel integration package to provide a seamless experience. Check out the Laravel integration guide for more details.
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
- The `myapp.allow_direct_modification` setting controls whether direct modifications are allowed. This extension manages this setting internally and resets it after each operation.
|
||||||
|
- Ensure that only trusted users have permission to execute the functions in this extension.
|
||||||
|
- For maximum security, consider revoking direct INSERT, UPDATE, and DELETE permissions on secure tables for application users.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT License - see the LICENSE file for details.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
1421
c77_secure_db--1.0.0.sql
Normal file
1421
c77_secure_db--1.0.0.sql
Normal file
File diff suppressed because it is too large
Load Diff
5
c77_secure_db.control
Normal file
5
c77_secure_db.control
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# c77_secure_db extension control file
|
||||||
|
comment = 'Secure database operations with tamper detection and transaction control'
|
||||||
|
default_version = '1.0.0'
|
||||||
|
relocatable = false
|
||||||
|
requires = 'pgcrypto'
|
Loading…
x
Reference in New Issue
Block a user