Keep the secrets out of emails and chat history!
Flash is a tiny web service for sharing the secrets in a secure way.
While sending passwords, API tokens or other sensitive piece of information over email or chat is known to be a bad practice from security point of view, it keeps happening over and over due to its convenience.
This project aims to solve the problem of "how to transfer the secret from person A to person B in both hassle-free and secure way".
The project was inspired by Magic Wormhole, and while they both have similar end-goal, Flash solves the problem with different means (and thus different trade-offs). See Goals/non-goals section for more about that.
Flash solves the stated problem by temporarily storing the secrets under single-use, time limited, private links, which can be shared over email or chat.
- Open Flash in your web browser
- Paste your secret
- Copy resulting secret link
- Share the link with a person you'd like to know your secret
Every secret link contains unguessable, random token, which uniquely points to a secret. When the link is opened by the recipient it warns them about ephemeral nature of the link, and after confirmation it displays the secret content. At this point the secret is removed from the storage and can't be retrieved from Flash ever again. It's burned after reading :)
Each secret is kept in the storage for limited amount of time (TTL), which is selected when creating the secret link (several options from 5 minutes to 7 days). If the link is not used within selected TTL then the secret is automatically removed from the storage and the link will not work anymore.
See Security section for more in-depth information about security model of this project.
- Keep it simple, small and focused on the essential problem,
- Make secret sharing asynchronous - both parties don't have to be online at the same time,
- Keep it friendly for non-developers.
The last two goals make it quite different from how Magic Wormhole operates (an inspiration for this project). Wormhole runs in terminal, and while this is natural for developers, it's quite a barrier for non-developer types (e.g. other roles in your organization). Flash is accessible by anyone with a web browser. Wormhole is synchronous (P2P) - requires both parties to be online when sharing happens, which allows it to not store the secrets at all. Flash is async, which is more convenient for the user, but requires storing the secrets (temporarily, encrypted). It's a conscious trade-off which was chosen here.
Following features are not planned as they stand against the chosen security model:
- Multi-use links
- Non-expiring links
- E2E (end-to-end) encryption
Following sections describe implemented security means, trade-offs and considerations taken when developing this project.
... not E2E
Secret links contain 21 character long token which is used to lookup the secret in the storage. The token is random and has no relation to the secret content, and so it cannot be used to retrieve the secret after the secret has been read or expired.
In case of the link falling into the wrong hands the person who created it can burn it immediately (there's button for that on the page with sharing instructions of a given link). If the unintended recipient already read the secret it obviously can't be undone. However, if one reacts quickly this gives them a chance to prevent the leakage. The "burn" button gives feedback whether the secret was burned or it doesn't exist anymore (either already read or expired).
Given the token embedded in the secret link is the only thing needed to retrieve the actual secret it's essential to use HTTPS to avoid MITM attacks. Flash defaults to HTTPS protocol, and if you really want HTTP (highly discouraged) you need to configure it explicitly.
The actual secret content is encrypted with AES-GCM (using 256-bit key) and saved in the configured storage backend (see Persistence for storage options).
Given that stored data is short-lived there isn't a real need for configuring backups of the storage backend database.
In case of the database contents getting exposed to some 3rd party (you use managed database service with automatic backups by service provider, or someone obtained a copy of database contents via other means) the secrets are safe as long as this 3rd party doesn't also have access to the configured encryption key (see Configuration).
To put the above another way: in order to get access to the secrets one needs to have access to the encryption key and the storage database.
- rate limiting to prevent brute-force attacks to find tokens
- CSRF protection: SameSite cookie + CSRF token
- HSTS + no iframe headers
Flash doesn't implement E2E encryption, and given the domain it operates in (secure transfer of sensitive data) it's recommended to be self-hosted. You should not use any public instances of Flash, for purposes other than testing.
TODO: document
It is recommended to self-host Flash (run your own instance), and the easiest way to run it is to use Docker.
You can build Docker image for the latest version like this:
git clone https://github.com/sickill/flash.git
cd flash
docker build -t sickill/flash .
There's also automated Docker Hub build configured for this project, which generates sickill/flash image.
You can run flash locally, in insecure "demo mode" like this:
docker run -p 4000:4000 -e URL_SCHEME=http -e URL_PORT=4000 sickill/flash
Open http://localhost:4000 to access the app.
This is INSECURE (no HTTPS and no persistence), so do this only if you want to play with it locally.
Recommended, "production" setup would be to run it like this:
docker run -p 4000:4000 -e URL_HOST=flash.example.com sickill/flash
The above assumes that there's a proxy/web server configured for
flash.example.com
domain, which handles HTTPS and proxies all requests to
port 4000 of the container.
NOTE: This is minimal secure setup, however stored secrets are not persisted and they will be lost upon container restart. See Persistence below for more robust setup.
You can get HTTPS up and running very easily with Caddy web server. Caddy handles Let's Encrypt certificate requesting/renewal automatically. Check out included docker-compose file for example setup.
Following env variables can be used to configure the service:
SECRET_KEY_BASE
- base secret token for encryption/signing, min. 64 chars long. Default: random key generated on bootENCRYPTION_KEY
- encryption key, 32 chars long. Default: first 32 chars ofSECRET_KEY_BASE
are used as encryption keyPORT
- HTTP listener port number. Default: 4000REDIS_URL
- Redis server to use for secrets storage. Default: noneURL_SCHEME
- scheme for URL generation. Default: httpsURL_HOST
- host for URL generation. Default: localhostURL_PORT
- port for URL generation. Default: 443DEFAULT_TTL
- default value for TTL input, in seconds. Default: 3600ADMIN_USERNAME
- basic auth username for access to admin section. Default: adminADMIN_PASSWORD_SHA1
- SHA1 hex digest of the password for above user. Default: none
This project is built with Elixir language and Phoenix web framework.
To start developing:
- Install Erlang, Elixir and Node.js for your platform
- Run
mix setup
to fetch and build dependencies - Run
mix test
to run the test suite - Run
iex -S mix phx.server
to startiex
shell with embedded web server - Visit
localhost:4000
from your browser to access the site
Copyright 2020 Marcin Kulik
This project is licensed under the Apache License, Version 2.0.
The authors of this project are not responsible for any data loss, leakage of sensitive information or any other damages due to use of this software. USE AT YOUR OWN RISK.