Comments (8)
This is very interesting. Here are a few thoughts:
- This is slightly related to #32, which also deals with a security by adding a prefix
- This is indeed a security flaw, but REDIS is designed "to be accessed by trusted clients inside trusted environments", and implementing this adds complexity to this project, which maybe should be implemented somewhere else
- If we decide to encrypt the values, I think your solution has a good design.
<secret><seperator><key>
is a good way of making the store values ciphered, and the secret shouldn't be available in the store.
Overall, I think this is a good idea. I especially like that we can implement this without breaking API backwards compatibility, and essentially making it transparent to users.
If you were to make a PR, I will gladly review and consult.
I will also ask a member of our security team to take a look at this design
from snappass.
I'm not sure I understand. Let's call secret what the user wants to share, and key the proposed encryption key.
Current solution is to store secret
.
Proposed solution is to store key<separator>secret
.
Am I understanding correctly?
If so, then I don't think the solution will add much in terms of security because anyone accessing key<separator>secret
can separate, get key
and use it to decrypt secret
. (when reasoning about security, you need to assume the attacker knows the algorithms used, in particular here that the code is opensource).
The solution would be good if we could transmit key
from userA to userB without storing it into Redis. This said, if we had such a channel, we could just use it to share secret
in the first place.
from snappass.
As @nichochar pointed out, this was probably excluded from the original threat model of snappass, but it seems like an overall improvement.
Given the security architecture of redis, read access generally means write access (unless we are referring to backups). So we should also think about threats against availability and integrity. Not much we can do against an availability attack, but for integrity we could make it AEAD (with AES-GCM or something similar) and include the redis key id in the associated data. Not sure what a realistic attack would look like in the integrity arena and confidentiality is the most serious threat for this kind of system, but its still probably a good idea.
We should also note that attackers with access to browsing history of a targeted user and redis will be able to decrypt secrets (query parameters are stored in history). We can only enforce the exactly once nature of the system in the scenario where redis is compromised if there is a server side secret that we can assume is not compromised and is used in the encryption process and we are using authenticated encryption with the redis key in the associated data. The server side secret would need to be combined with the client side secret to derive a key using some sort of secure key derivation algorithm like shamir's secret sharing (probably not the ideal choice but a popular one).
We should make sure AEAD keys are generated using a secure random number generator (/dev/urandom or the like) and AEAD keys are never sent to the redis server.
from snappass.
Thanks for the input @0x0ece, @devinlundberg
So to sum up:
- if we assume the attacker knows the algorithm, this really doesn't protect the password
- if we assume they don't, or people are "looking into the values of the REDIS DB" by accident, then it adds a slight layer of obfuscation.
The question now is: do we think this is a tradeoff that is worth doing?
From what I can tell, there are no downsides, but the upsides are very slight. Does anybody have a strong opinion on whether this should be implemented, or not?
from snappass.
We had a separated chat.
One possible solution is the following.
Generate a key
which is never stored in Redis, but only passed between users. This can be an arbitrarily long random bit string.
Encrypt secret
with key
, e.g. using xor (one-time pad).
Store enc(secret)
in Redis. In this way, an attacker accessing the db can't read any secret.
Transmit key
to the other party, e.g. make it a param in the shared url. Note that an attacker reading the key could access the secret. The "protection" here comes from the fact that secret will be deleted after 1 consumption, so only one between the user and the attacker will get the secret, whoever arrives first.
In short, we're assuming that the channel between users is trusted enough to pass a short-lived key, but not longterm to transmit a secret that may be valid for more time. Think for instance to Slack, you trust it to share the key via chat, but you don't know what happens to their servers in the long term, so you don't want your actual secret to be stored there indefinitely.
Also, implementation caveat. If we expire the secret after 1 consumption, we need to make sure that the "channel" doesn't offer (or isn't allowed) to do url preview (again, think to Slack), for example via robots.txt or assuming snappass is on a private network.
from snappass.
Thanks all for the quick and thorough feedback!
I like the idea of server and client-side encryption, I had never thought of that...
@0x0ece I think you misunderstood my idea, it's probably because of my terminology.
Let me extend on your approach, and get some definitions in here :)
Sender - user that wants to share a secret/password;
Receiver - user Sender shares the link with;
secret - What Sender wants to share;
secret ID - Unique identifier of the secret;
encryption key - Key used to encrypt the secret, and decrypt the encrypted secret;
encrypted secret - Secret encrypted with the encryption key (also referred to as "cypher text");
Currently, the algorithm is:
- Sender sends the secret in a POST request to SnapPass;
- SnapPass randomly generates a unique secret ID;
- SnapPass stores the secret in plain text in Redis, with the secret ID as the key (key as in key-value!);
- SnapPass responds to Sender with a link containing the secret ID;
- Sender sends the link to Receiver;
- Receiver sends a GET request with the secret ID to SnapPass;
- SnapPass looks up the secret ID in Redis, retrieves the secret;
- SnapPass sends the secret to Receiver.
What is stored: secret
What is given back to Sender: secret ID
Contrast with my suggested implementation:
- Sender sends the secret in a POST request to SnapPass;
- SnapPass randomly generates a unique encryption key;
- SnapPass encrypts the secret with the encryption key, generating the encrypted secret
- SnapPass stores the encrypted secret in in Redis, with the secret ID as the key (key as in key-value!);
- SnapPass responds to Sender with a link containing both the secret ID and the encryption key;
(That's where the separator comes in, as a way to have both in the link) - Sender sends the link to Receiver;
- Receiver sends a GET request with the secret ID and encryption key to SnapPass;
- SnapPass lookup the secret ID in Redis, to retrieve the encrypted secret;
- SnapPass uses the encryption key to decrypt the encrypted secret, recovering the secret.
- SnapPass sends the secret to Receiver.
What is stored: encrypted secret
What is given to back Sender: secret ID + encryption key
This means people can know the algorithm, but they wouldn't be able to retrieve the value just from Redis.
What they need is the key, which SnapPass doesn't have.
An attacker would need to have both access to Redis and the link that was generated,
in order to get the password without expiring the link.
So it's not mere obfuscation, it's really encryption!
@devinlundberg I think this also addresses the browser history part (?), since the encryption key is unique for every request.
The link never makes it to Sender's browser history, and when it makes it into Receiver's browser history,
it has already been consumed and so it's too late!
It would however be possible for the attacker to hijack the browser and intercept the link,
but at this point there won't be any chance of securely sharing anything for poor Sender...
The value I saw to the addition, initially:
- If an attacker breaks on my servers, a Redis dump won't reveal any data;
- I don't have to rely on the fact that my sysadmin/public cloud employees/K8s cluster maintainers/etc. won't peep inside Redis;
from snappass.
@0x0ece I read your last message after posting mine, sigh. I think we are converging on a solution.
Some notes:
- Passing an arbitrary long key in a URL might not work for all usages, because the length has an upper bound.
- Consumption by URL preview and bots is indeed problematic, and was partially addressed in a previous PR (#46) for a number of known User-Agents.
robots.txt
is a pretty interesting addition though, since it protects more consistently for well-behaved robots. Another option is to use the app/API distinction I know is also being worked on. If you use a channel with URL preview, you can send a link to a page that will have a "reveal" button to show the secret after calling the API.
from snappass.
@samueldg All you added LGTM.
from snappass.
Related Issues (20)
- Where to host this HOT 1
- Use of SECRET_KEY HOT 2
- .NET port
- How secure is the docker-compose approach? HOT 2
- feature request: i18n HOT 3
- URL_PREFIX is ignored HOT 3
- feature request: Prevent crawler from opening / invalidate secret HOT 2
- Simple setup question HOT 1
- Snappass config for apache webserver
- docker hub 404 HOT 1
- Stack Error when trying to start SnapPass HOT 3
- Official method of securing this with HTTPS? HOT 2
- Question about creation of multiple links HOT 6
- Any way to change the URL of the links that the Docker Container SnapPass spits out? HOT 7
- New release?
- Upgrade to JQuery version HOT 2
- Docker Build not working anymore HOT 3
- Help with the URL
- Unable to use API endpoints HOT 1
- "This is a development server"
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from snappass.