Revise README for improved clarity and detail
Updated README to enhance clarity and structure, added detailed features, installation instructions, and security analysis.
This commit is contained in:
@@ -1,2 +1,485 @@
|
||||
# Secure-Pastebin-Self-Hosted
|
||||
🔐 Secure Pastebin (Self-Hosted Ver) — End-to-End Encrypted Message Sharing. Zero-knowledge, password protected, self-destructing. Live demo: https://sphost.theazizi.ir #InternetForAll
|
||||
# 🔐 Secure Pastebin
|
||||
|
||||
> **Self-Hosted, Zero-Knowledge, End-to-End Encrypted Pastebin**
|
||||
>
|
||||
> Share sensitive messages securely. Server cannot read your data. Ever.
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://php.net)
|
||||
[](https://en.wikipedia.org/wiki/Galois/Counter_Mode)
|
||||
[](#)
|
||||
[](#)
|
||||
|
||||
🌐 **Live Demo:** https://sphost.theazizi.ir
|
||||
☁️ **Cloudflare Worker Version:** [IP-Security-Analyzer-Cloudflare-Worker](https://github.com/TheGreatAzizi/IP-Security-Analyzer-Cloudflare-Worker)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Features](#-features)
|
||||
- [Cryptography Architecture](#-cryptography-architecture)
|
||||
- [Installation](#-installation)
|
||||
- [Database Structure](#-database-structure)
|
||||
- [API Reference](#-api-reference)
|
||||
- [Security Analysis](#-security-analysis)
|
||||
- [Browser Compatibility](#-browser-compatibility)
|
||||
- [Deployment Comparison](#-deployment-comparison)
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
|
||||
| Feature | Description | Security Impact |
|
||||
|---------|-------------|---------------|
|
||||
| 🔒 **E2E Encryption** | AES-256-GCM in browser before transmission | Server sees only ciphertext |
|
||||
| 🛡️ **Zero-Knowledge** | Server has zero access to keys or plaintext | Mathematically provable |
|
||||
| 🔑 **Password Protection** | PBKDF2 with 100,000 iterations | Brute-force resistant |
|
||||
| 🔥 **Burn After Read** | Auto-delete after first access | Forward secrecy |
|
||||
| ⏱️ **Auto-Expiration** | 1 hour to 30 days configurable | Limits exposure window |
|
||||
| 🌐 **RTL Support** | Persian, Arabic, Hebrew typography | Accessibility |
|
||||
| 📱 **Responsive** | Mobile-first design | Usability |
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Cryptography Architecture
|
||||
|
||||
### Zero-Knowledge Proof
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ZERO-KNOWLEDGE GUARANTEE │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ USER BROWSER SERVER / DATABASE │
|
||||
│ ───────────── ───────────────── │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │ Generate │ ──NOT SENT──────► │ │ │
|
||||
│ │ AES-256 Key │ │ NO KEYS STORED │ │
|
||||
│ └─────────────┘ │ │ │
|
||||
│ └─────────────────┘ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ Encrypt │ ──NOT SENT────────────────────────────────────►│
|
||||
│ │ Plaintext │ │
|
||||
│ │ with Key │ │
|
||||
│ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │ Send: │ ──HTTPS─────────► │ Store: │ │
|
||||
│ │ • ID │ │ • ID │ │
|
||||
│ │ • IV │ │ • IV │ │
|
||||
│ │ • Ciphertext│ │ • Ciphertext │ │
|
||||
│ │ • Metadata │ │ • Metadata │ │
|
||||
│ └─────────────┘ │ │ │
|
||||
│ │ NO PLAINTEXT │ │
|
||||
│ ┌─────────────┐ │ NO PASSWORD │ │
|
||||
│ │ Key Stored │ │ NO KEY │ │
|
||||
│ │ in URL: │ │ │ │
|
||||
│ │ │ └─────────────────┘ │
|
||||
│ │ #id:key ◄─┘ NEVER in HTTP headers │
|
||||
│ │ │ │
|
||||
│ └─────────────┘ Fragment not sent to server │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Technical Specifications
|
||||
|
||||
| Component | Standard | Parameters |
|
||||
|-----------|----------|------------|
|
||||
| Symmetric Encryption | AES-256-GCM | 256-bit key, 96-bit nonce |
|
||||
| Key Derivation | PBKDF2 | 100,000 iterations, SHA-256 |
|
||||
| Random Generation | CSPRNG | Crypto.getRandomValues() |
|
||||
| Key Encoding | Base64URL | URL-safe, no padding |
|
||||
| Transport Security | TLS 1.3 | Certificate pinning recommended |
|
||||
|
||||
### Encryption Flow
|
||||
|
||||
```javascript
|
||||
// 1. Key Generation (Browser)
|
||||
const key = await crypto.subtle.generateKey(
|
||||
{ name: 'AES-GCM', length: 256 },
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
);
|
||||
|
||||
// 2. Encryption (Browser - before network)
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12));
|
||||
const ciphertext = await crypto.subtle.encrypt(
|
||||
{ name: 'AES-GCM', iv },
|
||||
key,
|
||||
new TextEncoder().encode(plaintext)
|
||||
);
|
||||
|
||||
// 3. Transmission (HTTPS only)
|
||||
fetch('/api/create', {
|
||||
body: JSON.stringify({
|
||||
id: randomId,
|
||||
encryptedData: { iv: [...iv], data: [...ciphertext] },
|
||||
// NO KEY HERE - key stays in browser/URL
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
### System Requirements
|
||||
|
||||
| Requirement | Minimum | Recommended |
|
||||
|-------------|---------|-------------|
|
||||
| PHP | 7.4 | 8.1+ |
|
||||
| MySQL | 5.7 | 8.0+ |
|
||||
| Web Server | Apache 2.4 | Nginx + Apache |
|
||||
| SSL | Required | Let's Encrypt |
|
||||
|
||||
### Step 1: Database Setup
|
||||
|
||||
```sql
|
||||
CREATE DATABASE IF NOT EXISTS secure_pastebin
|
||||
CHARACTER SET utf8mb4
|
||||
COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
USE secure_pastebin;
|
||||
|
||||
CREATE TABLE pastes (
|
||||
id VARCHAR(32) PRIMARY KEY,
|
||||
data TEXT NOT NULL,
|
||||
created_at BIGINT NOT NULL,
|
||||
expires_at BIGINT NOT NULL,
|
||||
burn_after_read TINYINT(1) DEFAULT 0,
|
||||
has_password TINYINT(1) DEFAULT 0,
|
||||
views INT DEFAULT 0,
|
||||
INDEX idx_expires (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### Step 2: Configuration
|
||||
|
||||
Edit `index.php` (lines 5-8):
|
||||
|
||||
```php
|
||||
define('DB_HOST', 'localhost');
|
||||
define('DB_USER', 'your_cpanel_username_dbuser');
|
||||
define('DB_PASS', 'your_secure_random_password');
|
||||
define('DB_NAME', 'your_cpanel_username_pastebin');
|
||||
```
|
||||
|
||||
### Step 3: File Upload
|
||||
|
||||
```
|
||||
/public_html/pastebin/
|
||||
├── index.php # API backend + router
|
||||
├── index.html # Single-page application
|
||||
├── style.css # Complete styling (RTL included)
|
||||
├── script.js # Web Crypto implementation
|
||||
├── .htaccess # URL rewriting rules
|
||||
└── database.sql # Schema (already imported)
|
||||
```
|
||||
|
||||
### Step 4: SSL Enforcement
|
||||
|
||||
**cPanel Method:**
|
||||
1. SSL/TLS Status → Run AutoSSL
|
||||
2. Force HTTPS Redirect: ON
|
||||
|
||||
**Cloudflare Method:**
|
||||
1. DNS proxied through Cloudflare
|
||||
2. SSL/TLS mode: Full (strict)
|
||||
3. Always Use HTTPS: ON
|
||||
|
||||
### Step 5: Verification Checklist
|
||||
|
||||
- [ ] `https://yoursite.com/pastebin/` loads without mixed content warnings
|
||||
- [ ] Database connection successful (check error logs)
|
||||
- [ ] `POST /api/create` returns 201 with valid JSON
|
||||
- [ ] `GET /api/get/{id}` returns encrypted data
|
||||
- [ ] Auto-cleanup: Expired rows delete automatically
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Database Structure
|
||||
|
||||
### Schema Overview
|
||||
|
||||
| Column | Type | Nullable | Description |
|
||||
|--------|------|----------|-------------|
|
||||
| `id` | VARCHAR(32) | NO | Cryptographically random hex |
|
||||
| `data` | TEXT | NO | JSON: {iv: number[], data: number[]} |
|
||||
| `created_at` | BIGINT | NO | Unix timestamp (ms) |
|
||||
| `expires_at` | BIGINT | NO | Auto-deletion trigger (s) |
|
||||
| `burn_after_read` | TINYINT(1) | NO | Boolean flag |
|
||||
| `has_password` | TINYINT(1) | NO | PBKDF2 required flag |
|
||||
| `views` | INT | NO | Access counter |
|
||||
|
||||
### Real-World Example
|
||||
|
||||
**User Input:**
|
||||
```
|
||||
سلام، این پیام محرمانه من است.
|
||||
Hello, this is my secret message.
|
||||
```
|
||||
|
||||
**What Gets Stored in Database:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "7a3f9e2b8c1d4e5f6a7b8c9d0e1f2a3b",
|
||||
"data": "{\"iv\":[187,45,92,201,78,34,156,89,234,12,67,189],\"data\":[45,189,234,67,123,89,45,234,89,123,45,67,234,89,123,45,67,234,89,123,45,67,234,89,123,45,67,234,89,123,45,67,234,89,123,45,67,234,89,123,45,67,234,89,123,45]}",
|
||||
"created_at": 1708368000000,
|
||||
"expires_at": 1708454400,
|
||||
"burn_after_read": 0,
|
||||
"has_password": 1,
|
||||
"views": 0
|
||||
}
|
||||
```
|
||||
|
||||
**URL Generated (CONTAINS KEY):**
|
||||
```
|
||||
https://yoursite.com/#7a3f9e2b8c1d4e5f6a7b8c9d0e1f2a3b:c2FsdHNhbHRzYWx0:pwd
|
||||
↑ ↑
|
||||
Base64URL salt Password flag
|
||||
(for PBKDF2)
|
||||
```
|
||||
|
||||
**Critical Security Note:**
|
||||
- The URL fragment (`#...`) is **never sent** in HTTP headers
|
||||
- Server logs contain: `GET /api/get/7a3f9e2b8c1d4e5f6a7b8c9d0e1f2a3b`
|
||||
- Server logs **never contain**: The key, plaintext, or password
|
||||
|
||||
---
|
||||
|
||||
## 🔧 API Reference
|
||||
|
||||
### Authentication
|
||||
|
||||
No authentication required. Security through cryptography, not access control.
|
||||
|
||||
### Endpoints
|
||||
|
||||
#### POST `/api/create`
|
||||
|
||||
Create new encrypted paste.
|
||||
|
||||
**Headers:**
|
||||
```
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"id": "a1b2c3d4e5f6... (32 hex characters)",
|
||||
"encryptedData": {
|
||||
"iv": [12, 34, 56, 78, 90, 12, 34, 56, 78, 90, 12, 34],
|
||||
"data": [189, 45, 78, 201, 156, 78, 33, 45, 182, 91, 234, 12, 67]
|
||||
},
|
||||
"expiresIn": 86400,
|
||||
"burnAfterRead": false,
|
||||
"hasPassword": false
|
||||
}
|
||||
```
|
||||
|
||||
**Success Response (201):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"id": "a1b2c3d4e5f6...",
|
||||
"expiresIn": 86400,
|
||||
"hasPassword": false,
|
||||
"url": "https://yoursite.com/#a1b2c3d4e5f6:base64urlEncodedKey"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
| Code | Condition | Response |
|
||||
|------|-----------|----------|
|
||||
| 400 | Invalid ID format | `{"error": "Invalid ID format"}` |
|
||||
| 400 | Malformed JSON | `{"error": "Invalid JSON"}` |
|
||||
| 400 | Missing encryptedData | `{"error": "Invalid encrypted data format"}` |
|
||||
| 500 | Database failure | `{"error": "Failed to save paste"}` |
|
||||
|
||||
#### GET `/api/get/{id}`
|
||||
|
||||
Retrieve encrypted paste by ID.
|
||||
|
||||
**Parameters:**
|
||||
| Name | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `id` | string | 32-character hexadecimal ID |
|
||||
|
||||
**Success Response (200):**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"iv": [12, 34, 56, 78, 90, 12, 34, 56, 78, 90, 12, 34],
|
||||
"data": [189, 45, 78, 201, 156, 78, 33, 45, 182, 91, 234, 12, 67]
|
||||
},
|
||||
"burnAfterRead": false,
|
||||
"hasPassword": false,
|
||||
"created": 1708368000000
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
| Code | Condition |
|
||||
|------|-----------|
|
||||
| 400 | Invalid ID format |
|
||||
| 404 | Paste not found or expired |
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Security Analysis
|
||||
|
||||
### Threat Model Matrix
|
||||
|
||||
| Attacker Capability | Data Access | Mitigation Status |
|
||||
|---------------------|-------------|-------------------|
|
||||
| **Passive network observer** | Encrypted TLS traffic only | ✅ Mitigated (TLS 1.3) |
|
||||
| **Database breach** | Ciphertext, metadata only | ✅ Mitigated (no keys stored) |
|
||||
| **Server compromise (root)** | Same as database | ✅ Mitigated (stateless design) |
|
||||
| **Backup tape theft** | Historical ciphertext | ✅ Mitigated (keys not in backups) |
|
||||
| **URL leak (no password)** | Full plaintext | ⚠️ **User responsibility** |
|
||||
| **URL leak (with password)** | Partial (needs password) | ⚠️ **Reduced risk** |
|
||||
| **Physical device access (post-decrypt)** | Plaintext in memory | ❌ **Not mitigated** |
|
||||
|
||||
### What We Protect Against
|
||||
|
||||
1. **Server-side attacks**: Even with full server compromise, attacker gains zero cryptographic material
|
||||
2. **Legal requests**: No plaintext or keys to surrender (technical impossibility)
|
||||
3. **Insider threats**: System administrators cannot access user content
|
||||
4. **Database leaks**: Ciphertext without keys is information-theoretically secure
|
||||
|
||||
### What We Cannot Protect Against
|
||||
|
||||
1. **Endpoint compromise**: Malware on sender/recipient device
|
||||
2. **Social engineering**: Users tricked into sharing URLs
|
||||
3. **Shoulder surfing**: Visual observation of decrypted content
|
||||
4. **Forensic analysis**: RAM dumps containing decrypted plaintext
|
||||
|
||||
### Operational Security Recommendations
|
||||
|
||||
| Risk | Mitigation Strategy |
|
||||
|------|---------------------|
|
||||
| URL in browser history | Use incognito/private mode |
|
||||
| URL in cloud sync | Disable browser sync for sensitive operations |
|
||||
| Screenshot exposure | Enable "Burn After Read" |
|
||||
| Password guessing | Use 12+ character random passwords |
|
||||
| Keylogger exposure | Use hardware security keys where possible |
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Browser Compatibility
|
||||
|
||||
| Browser | Version | Web Crypto API | Status |
|
||||
|---------|---------|----------------|--------|
|
||||
| Chrome | 37+ | ✅ Full | Recommended |
|
||||
| Firefox | 34+ | ✅ Full | Recommended |
|
||||
| Safari | 7+ | ✅ Full | Supported |
|
||||
| Edge | 12+ | ✅ Full | Supported |
|
||||
| Opera | 24+ | ✅ Full | Supported |
|
||||
| Internet Explorer | Any | ❌ None | Not Supported |
|
||||
|
||||
**Requirement:** Secure context (HTTPS or `localhost`) mandatory for `crypto.subtle` access.
|
||||
|
||||
---
|
||||
|
||||
## ⚖️ Deployment Comparison
|
||||
|
||||
### Self-Hosted (This Repository) vs Cloudflare Worker
|
||||
|
||||
| Dimension | Self-Hosted | Cloudflare Worker |
|
||||
|-----------|-------------|-------------------|
|
||||
| **Infrastructure** | Your server/cPanel | Cloudflare Edge Network |
|
||||
| **Data Sovereignty** | Full control | Third-party processing |
|
||||
| **Latency** | Server location dependent | Global edge (<50ms) |
|
||||
| **Scalability** | Vertical scaling | Auto-scaling |
|
||||
| **Setup Complexity** | Database + SSL required | Zero configuration |
|
||||
| **Cost** | Hosting fees | Free tier generous |
|
||||
| **Compliance** | GDPR/HIPAA self-managed | DPA required |
|
||||
| **Availability** | Your SLA responsibility | 99.99% Cloudflare SLA |
|
||||
|
||||
**Recommendation:**
|
||||
- Choose **Self-Hosted** for: Data sovereignty, compliance requirements, learning
|
||||
- Choose **Cloudflare Worker** for: Global reach, zero maintenance, speed
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
### Security Disclosure Policy
|
||||
|
||||
**DO NOT** open public issues for security vulnerabilities.
|
||||
|
||||
Responsible disclosure:
|
||||
1. Email: security@yourdomain.com
|
||||
2. GPG Key: [0xYOURKEYFingerprint]
|
||||
3. Response time: 48 hours
|
||||
4. Bounty: Varies by severity
|
||||
|
||||
### Development Setup
|
||||
|
||||
```bash
|
||||
# Local HTTPS testing
|
||||
npx mkcert localhost 127.0.0.1
|
||||
npx serve . --ssl-cert localhost.pem --ssl-key localhost-key.pem
|
||||
|
||||
# Or PHP built-in (limited, no HTTPS)
|
||||
php -S localhost:8000
|
||||
```
|
||||
|
||||
### Code Standards
|
||||
|
||||
- PSR-12 for PHP
|
||||
- ES2020 for JavaScript
|
||||
- BEM for CSS
|
||||
- All crypto operations must use Web Crypto API (no custom crypto)
|
||||
|
||||
---
|
||||
|
||||
## 📜 License & Attribution
|
||||
|
||||
**License:** MIT License - See [LICENSE](LICENSE)
|
||||
|
||||
**Cryptographic Implementation:**
|
||||
- Web Crypto API W3C Specification
|
||||
- NIST SP 800-132 (PBKDF2)
|
||||
- FIPS 197 (AES)
|
||||
|
||||
**Typography:**
|
||||
- Vazirmatn by Saber Rastikerdar (Persian/Arabic script support)
|
||||
|
||||
**Inspiration:**
|
||||
- PrivateBin (PHP implementation)
|
||||
- ZeroBin (original concept)
|
||||
- CryptPad (collaborative editing)
|
||||
|
||||
---
|
||||
|
||||
**⚠️ Legal Disclaimer**
|
||||
|
||||
> THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. The authors and contributors assume no liability for data loss, security breaches, or misuse. Users are solely responsible for:
|
||||
> - Key management and storage
|
||||
> - Operational security practices
|
||||
> - Compliance with local laws and regulations
|
||||
> - Secure transmission of URLs and passwords
|
||||
|
||||
---
|
||||
|
||||
## 📊 Quick Stats
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Encryption strength | 256-bit |
|
||||
| Key derivation iterations | 100,000 |
|
||||
| IV length | 96-bit (12 bytes) |
|
||||
| Maximum message size | Limited by browser memory (~2GB) |
|
||||
| Supported languages | All Unicode (UTF-8) |
|
||||
| Database overhead | ~2x plaintext size (JSON + Base64) |
|
||||
|
||||
---
|
||||
|
||||
**Made with 🔒 in [Your Location]**
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user