security section in readme
This commit is contained in:
30
README.md
30
README.md
@@ -121,6 +121,36 @@ The tools people use to communicate should belong to the people using them. Not
|
|||||||
- HSTS, CSP, and all the security headers you'd expect
|
- HSTS, CSP, and all the security headers you'd expect
|
||||||
- Automatic database migrations on startup
|
- Automatic database migrations on startup
|
||||||
|
|
||||||
|
## 🛡️ Security
|
||||||
|
|
||||||
|
Letting people participate anonymously doesn't mean letting them run wild. Echoboard takes security seriously at every layer - protecting the people who give feedback, the people who manage it, and the data in between.
|
||||||
|
|
||||||
|
**Spam protection without surveillance.** Instead of CAPTCHAs - which are inaccessible, annoying, and train someone else's machine learning models with your users' labor - Echoboard uses ALTCHA proof-of-work challenges. The user's browser solves a small computational puzzle before submitting. It's invisible to real people and expensive for bots. No third-party scripts, no tracking pixels, no "select all the traffic lights."
|
||||||
|
|
||||||
|
**Encrypted at rest.** Display names and other personal data aren't stored as plain text in the database. Each field is individually encrypted with AES-256-GCM - even if someone gets access to your database, they can't read user identities without the encryption key. Lookups happen through blind indexes (HMAC-SHA256), so searches work without ever exposing the plaintext.
|
||||||
|
|
||||||
|
**Passwords never touch the wire in the clear.** Admin passwords are hashed with bcrypt (cost factor 12) before storage. Timing-safe comparisons prevent attackers from figuring out whether an email exists based on how long a login attempt takes. Failed login attempts trigger exponential backoff, making brute force impractical.
|
||||||
|
|
||||||
|
**Passkeys are phishing-proof.** Unlike passwords, passkeys use public-key cryptography. The private key never leaves the user's device - not to your server, not to anyone. Even if someone intercepts the authentication exchange, they can't replay it. There's nothing to phish, nothing to leak, nothing to stuff into a credential database.
|
||||||
|
|
||||||
|
**Recovery codes are single-use and hashed.** When a user generates a recovery phrase, the plaintext is shown once and never stored. What goes into the database is a bcrypt hash and a blind index. Even someone with full database access can't reverse the phrase. Each code works exactly once and expires after 90 days.
|
||||||
|
|
||||||
|
**Token blocklisting.** When someone logs out, changes their identity, or has their account deleted, their session tokens are immediately blocked. The blocklist is persistent (stored in the database, not in memory), so a server restart doesn't magically revalidate revoked sessions.
|
||||||
|
|
||||||
|
**Role-based access for the team.** Not every team member needs the same level of access. Super admins, admins, and moderators have different permissions, enforced server-side on every single request. A moderator can't escalate to admin by calling API endpoints directly - the backend checks your role before doing anything, not just the frontend.
|
||||||
|
|
||||||
|
**Invite links are single-use and expiring.** Team invites are hashed before storage, expire after a configurable window, and can only be claimed once. The claim happens inside a serializable database transaction, so even two simultaneous requests can't both succeed.
|
||||||
|
|
||||||
|
**Webhooks can't reach your internal network.** Outbound webhook delivery validates the destination URL against a blocklist of private IP ranges, resolves DNS before connecting (preventing rebinding attacks), and connects directly to the resolved IP with TLS verification. Your internal services stay invisible.
|
||||||
|
|
||||||
|
**Content security headers everywhere.** HSTS with a two-year max-age, strict CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy set to no-referrer. The embed widget runs in a sandboxed iframe. Custom CSS input is decoded and scanned before storage to prevent injection.
|
||||||
|
|
||||||
|
**File uploads are validated, not trusted.** Uploaded images are checked against magic byte signatures (not just file extensions or MIME types). Path traversal is prevented with realpath resolution. If a database insert fails after a file is written, the orphaned file is cleaned up automatically.
|
||||||
|
|
||||||
|
**Rate limiting on everything.** Every endpoint has a rate limit appropriate to its sensitivity - from 100/minute for general browsing down to 3/15 minutes for recovery code attempts. This isn't just a global throttle; each endpoint is tuned individually.
|
||||||
|
|
||||||
|
Security isn't a feature you bolt on at the end. It's a set of choices you make from the beginning about what data to collect (as little as possible), how to store it (encrypted), how to verify identity (without passwords when possible), and how to fail (safely, loudly, and without leaking information). Echoboard makes those choices so you don't have to think about them.
|
||||||
|
|
||||||
## 🚀 Getting started
|
## 🚀 Getting started
|
||||||
|
|
||||||
### 1. Clone and configure
|
### 1. Clone and configure
|
||||||
|
|||||||
Reference in New Issue
Block a user