Hey DEV Community! 👋
I recently launched SecretGate—a self-hostable, zero-knowledge ephemeral messaging platform designed to eliminate server-side trust and raw data exposure.
I wanted to build an alternative to traditional anonymous/ephemeral messaging tools (like NGL or Privnote) that actually guarantees privacy through math rather than a "trust us" policy.
Here is a breakdown of the technical decisions, architecture, and security model behind the project.
💡 Why Pure Native PHP & Zero Frameworks?
In a world dominated by massive node_modules trees and heavy framework dependencies, I intentionally built SecretGate using pure native PHP 8+.
- Zero Supply Chain Risk: No Composer dependencies to keep audited or updated.
- Minimal Audit Surface: Around 10 PHP files in total that any developer can read top-to-bottom in under an hour.
- Blazing Fast Performance: Runs seamlessly on standard LAMP/LEMP stacks with minimal resource footprint.
🔐 How Zero-Knowledge Encryption Works
SecretGate uses Hybrid Client-Side Encryption via the W3C Web Crypto API (window.crypto.subtle). The server acts purely as a dumb ciphertext store.
1. Link Creation (Recipient)
- The browser generates an RSA-OAEP (2048-bit) keypair.
- The private key is wrapped using an AES-256-GCM key derived from a user password via PBKDF2 (300,000 iterations).
- The encrypted private key is stored locally in the browser's IndexedDB vault and never transmitted to the server.
- Only the RSA Public Key (JWK) and an Argon2id password hash are sent to the server.
2. Message Transmission (Sender)
- When a sender visits a link, their browser fetches the recipient's public key.
- A single-use AES-256-GCM symmetric key encrypts the payload.
- The AES key is then encrypted with the recipient's RSA public key.
- Both ciphertexts are POSTed to the backend. The server stores data it mathematically cannot read.
3. Message Decryption (Recipient)
- The link owner unlocks their IndexedDB vault locally using their password.
- Decryption of the private key and subsequent message decryption happens entirely on-device inside the browser.
🛡️ Infrastructure & Backend Hardening
Even though encryption happens client-side, the backend stack is fully hardened against abuse:
- Database Safety: 100% prepared statements via PDO MySQL (zero raw SQL concatenation).
-
Session & CSRF Security: Per-session CSRF tokens, strict origin matching, and
HttpOnly/SameSite=Laxcookie flags. - Abuse Prevention: Redis-backed sliding-window rate limiting (auto-falls back to file-based storage if Redis is offline) and temporary IP burning.
-
Execution Isolation: Apache
.htaccessrules restrict PHP execution strictly to entry points (index.php,api.php), blocking direct access to.env,.sql, and backend scripts.
🚀 Live Demo & Open Source
SecretGate is completely 100% Open Source under the AGPL-3.0 License.
- 🌐 Live Demo: secretgate.site
- 💻 GitHub Repository: github.com/sasiru-mindaka/Secret-Gate
- 🔖 AlternativeTo: alternativeto.net/software/secretgate
💬 Feedback & Discussion
I’d love to get feedback from the DEV community!
How do you handle client-side cryptographic key storage in your projects? Any security improvements you'd suggest for the pipeline?
If you find SecretGate interesting or useful for self-hosting, dropping a ⭐ on the GitHub Repo would mean a lot!
Top comments (0)