Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False promises: end-to-end encryption is not effective #55

Closed
llebout opened this issue Jun 17, 2020 · 26 comments
Closed

False promises: end-to-end encryption is not effective #55

llebout opened this issue Jun 17, 2020 · 26 comments
Assignees
Labels
bug Something isn't working documentation Improvements or additions to documentation security signaling

Comments

@llebout
Copy link

llebout commented Jun 17, 2020

Hello!

Briefing is not end to end encrypted because the signaling server controls the trust given to WebRTC peers and their self-signed DTLS certificates. End to end encryption would require that key verification is done through a third party channel of the user's choice, otherwise the signaling server can create an intermediary key and spy on participants without any way for them to even know about it.

Please correct the description and so on to remove the mention of end-to-end encryption.

Thanks

@holtwick
Copy link
Owner

holtwick commented Jun 17, 2020

Thanks for your feedback, I appreciate that you are taking care of the correctness of the statements made in the app description.

I think we can agree, that a WebRTC connection is end-to-end encrypted, if the connection information (SDP) is exchanged securely. If I understand you correctly, your concern is that the users need to trust the signaling layer.

You might have seen, that the code of the signaling server is open source as well: https://github.com/holtwick/briefing/tree/master/signal

I understand if you now say: that's the source code, but how do I know if you installed exactly this code on the server? And you are right! You cannot know. Therefore I decided to make this project Open Source to enable anybody to set up his/her own environment she/he trusts.

With #1 I'm planning to programmatically give that trust independently of the installed code base. The idea is, that the peers communicate directly over a secure channel with direct e2ee through a password/key protected session.

For additional security related insights I would like to refer to: https://webrtc-security.github.io/

Also see discussions here: https://news.ycombinator.com/item?id=23523830

If you have ideas for improvements to strengthen the security and privacy of the project I would be very very happy to have you contributing to it! Thanks.

@llebout
Copy link
Author

llebout commented Jun 17, 2020

Open Source to enable anybody to set up his/her own environment she/he trusts

That's not end to end encryption if you need to trust a server, not everyone can set up a server, the point of end to end encryption is to distrust the server.

I think InsertableStreams are the way to go, just like Jitsi Meet did in a BETA feature. However, without that, it's not end to end encrypted, so please do not publish false promises that mislead users.

The other question is that whether the users can trust the web page. For that, I would advice making a companion browser extension that can verify the web page.

An example of such a companion browser extension is:

https://github.com/passbolt/passbolt_browser_extension

Another, more generic one is:

https://github.com/tasn/webext-signed-pages

An actual end to end encrypted service uses it:

https://www.etesync.com/faq/

Your web app is not end to end encrypted until it can meet those requirements.

@holtwick
Copy link
Owner

Ok, I get the point.

I don't think Insertable Streams are required, because these only solve problems with SFUs. A correctly established connection is still e2ee.

Therefore I'm planning to do the all communication, also the one via signal server, AES encrypted and validating the fingerprints of the SDP. Both parties need to have the same secret key.

Am I missing something? This should be sufficient to meet e2ee on the signaling layer as well.

@llebout
Copy link
Author

llebout commented Jun 18, 2020

@holtwick

I don't think you can access the DTLS certificate fingerprint from JavaScript.

You would need InsertableStreams here, because the WebRTC APIs are too high level and you cannot control how the signaling is used, if signaling is used to verify certificate fingerprints or not, etc.

You don't need "E2EE" on the "signaling layer" but key verification exposed to the users through the web interface so that the signaling layer is not trusted at all for anything else than making peers find each other.

You can display Emojis on screen that are the encoded version of a combination of both certificate fingerprints (if you can access them), and users can compare these Emojis through a third party channel, or through that very same call (it's an hard AI problem to modify voice or video in real time without ability for a human to notice, so it provides reasonable assurance).

In the case you can't access fingerprints, you would need to implement your own encryption on top, which is not so great. The signaling server doesnt need to be involved, you need to use InsertableStreams (because otherwise you cannot perform modifications on the media stream at all because it goes straight to the hardware encoder/decoder), and you can encrypt the stream with a pre-shared key (static key) which you can hash to avoid displaying secret key material on screen and then display Emojis for verification through channels of user's choice. I would advice against putting key material in a URL's fragment, I would instead advice to generate key material using a CSPRNG inside the browser (if there is one), and otherwise use an helper extension to access such a CSPRNG (like Passbolt does). The static key would have to be constructed and exchanged through a WebRTC data channel using Diffie-Hellman Key Exchange to avoid revealing the key material to someone who would spy the WebRTC session already and render the encryption useless because you gave away the key. Then hash the static key received from DH Key Exchange on both sides, encode as Emojis and display, and let users verify that the key is correct.

Currently, things are encrypted but they are not end to end encrypted. The trust provider is still the server, the server decides who trusts who and ultimately controls if encryption is effective or not.

The signaling server can create a third DTLS certificate, send the fingerprint to both parties and make both parties connect to a WebRTC peer that uses this DTLS certificate. That DTLS certificate would be trusted by both peers because the signaling server told them to do so, and both peers would think they are talking to each other directly but they are not. They are talking to this intermediary who justs records and forwards media.

@holtwick holtwick added documentation Improvements or additions to documentation security signaling labels Jun 18, 2020
@holtwick holtwick self-assigned this Jun 18, 2020
@holtwick
Copy link
Owner

Thanks a lot for your detailed feedback @leo-lb !

I don't think you can access the DTLS certificate fingerprint from JavaScript.

So the good news is, that fingerprints of connections are available. See https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/currentRemoteDescription And a quick test in Firefox and Chrome showed that they match as expected. IMO this is valid way to verify the point-to-point connection, if the signal exchange happens securely.

You can display Emojis on screen...

I like the idea of using Emojis to verify connections.

You don't need "E2EE" on the "signaling layer" but key verification exposed to the users through the web interface so that the signaling layer is not trusted at all for anything else than making peers find each other.

I believe that having E2EE for any communication, either directly or via signal server, is crucial. This will eliminate MitM attacks, because they need to get in between AND crack the secret key to join the communication.

I would advice against putting key material in a URL's fragment...

Fragments are not passed to any server and remain in the browser. Any connection is HTTPS or WSS anyway. Keys would of course be random keys or derivated like using PBKDF2 or similar.

The questions of trust and authorization/identity remain. But that's more a feature than a bug in Briefing's case.

@llebout
Copy link
Author

llebout commented Jun 18, 2020

I believe that having E2EE for any communication, either directly or via signal server, is crucial. This will eliminate MitM attacks, because they need to get in between AND crack the secret key to join the communication.

You are mistaken, "end to end encryption" is not "encryption" both are very different and with HTTPS and WSS this is standard client-server TLS encryption and not end to end encryption.

So the good news is, that fingerprints of connections are available. See https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/currentRemoteDescription And a quick test in Firefox and Chrome showed that they match as expected.

I can't see any fields for a DTLS certificate fingerprint there.

if the signal exchange happens securely.

It doesnt matter if it happens "securely" or not, end to end encryption removes the need for such. The signaling server can't be trusted at all. Mechanisms to distrust the signaling server have to be implemented client-side with cryptography for instance.

Fragments are not passed to any server and remain in the browser. Any connection is HTTPS or WSS anyway. Keys would of course be random keys or derivated like using PBKDF2 or similar.

Fragments are stored in the browser history in plain text, secret key material should never be stored that way! It's a very bad practice in general to expose key material in trivial UI components.

The questions of trust and authorization/identity remain. But that's more a feature than a bug in Briefing's case.

It's a bug because you claim that Briefing is end to end encrypted but it's not, yet.

@holtwick holtwick added the bug Something isn't working label Jun 18, 2020
@llebout
Copy link
Author

llebout commented Jun 18, 2020

@holtwick

Thank you for taking this issue seriously, many dismiss these needs and continue misleading users. I advice you clearly state that end to end encryption is pending implementation.

For example, people who dismiss end to end encryption effectiveness and continue to mislead users:

tutao/tutanota#768

They label such an issue as "improvement" when it's fundamental and contradictory to their own communication, in short, a lie!

@holtwick
Copy link
Owner

Thank you for taking this issue seriously

Of course! That was one of the main motivations to start the project and I want to make sure to reach that goal! And thank you for insisting, you are right it is misleading right now. I will change the claim if I do not get it fixed until weekend. I already started working on it.


Wikipedia: End-to-end encryption (E2EE) is a system of communication where only the communicating users can read the messages

That is what I want to achieve. I mentioned SSL to make clear, that the transport is secured as well. The data will be encrypted independently from that.

I can't see any fields for a DTLS certificate fingerprint there.

The object has an attribute sdp which contains a line starting with fingerprint=.

Fragments are stored in the browser history in plain text

That's a valid concern. I'll leave that decision to the user and make the implications clear. For some then convenience is also an argument.

BTW, I started documenting more in the Wiki. I will sum up security considerations, like this conversation, there as well. I'd like to be transparent in communication here. https://github.com/holtwick/briefing/wiki

@llebout
Copy link
Author

llebout commented Jun 18, 2020

The object has an attribute sdp which contains a line starting with fingerprint= .

That's great, the example on MDN did not show such a field, if it's different when you try it I am glad.

That's a valid concern. I'll leave that decision to the user and make the implications clear. For some then convenience is also an argument.

It doesnt have to affect convenience:

  • User creates a meeting URL
  • Both users join meeting URL
  • Both users have the webapp exchange key material through Diffie-Hellman Key Exchange
  • Both users are shown Emojis that correspond to hashed static key obtained the step above
  • Both users verify Emojis on a third party channel they trust, or directly through voice or video if relying on the hard AI problem that modifying voice and video real time without humans being able to notice is OK for them.

This works for 1:1, now for more people you would have to use multi party DH Key Exchange when a new participant joins or leaves, the Emojis will change, and everyone will have to confirm they see the same Emojis again.

Now the problem is to control whether key exchange happens or not, for 1:1 chats this is not a problem, but for group chats it is, you don't want the server itself to join to spy on users, so there needs to be some UI component for users to go ahead and approve a new participants in a group chat. In Jitsi Meet for example, anyone can kick anyone, so this would be a great thing, you require everyone to approve the new participant or kick them. When users are kicked they are shown a page where they can choose to rejoin (for example if they were AFK when a new key exchange had to happen).

This gets quite complicated, but it can only be.

What's clear to me is that storing key material in fragment is an important risk. If you can develop a companion web extension and require users to install it, I think that extension could prevent the fragment from being ever written in the history, not sure.

You would need a companion web extension anyway to provide trust in the code servers could be distributing. Without that, a server can trivially distribute malicious code selectively to specific users, code that can steal keys and send them back to the server without user noticing anything at all, a disaster.

@holtwick
Copy link
Owner

holtwick commented Jun 19, 2020

Ok, I made some progress. You can see and test the result at https://stage.brie.fi/ng

WebRTC fingerprints, as described before, are used to calculate a 16 bit checksum, represented as a 4 digit hex value. The steps are simple:

  1. Retrieve remote and local SDP fingerprints
  2. Sort them, thus the value is the same on both sides
  3. Calc simple checksum by sum up words and get the modulo of 0xffff

Currently the checksum is represented on the video and users can verify by reading the values aloud.

I also tried to manipulate the fingerprints and WebRTC was smart enough to refuse establishing a connection.

CleanShot 2020-06-19 at 10 04 49@2x

Source code available here: https://github.com/holtwick/briefing/tree/develop/app/src/logic

Looking forward for your feedback.

@llebout
Copy link
Author

llebout commented Jun 19, 2020

@holtwick

The reason to use Emojis is that they can represent a larger value in a representation that's easy to read for a human.

4 bytes is insufficient, it's trivial to generate a certificate that has the same 16-bit checksum but different fingerprint.

You need to use secure hashing, not checksums. Use SHA256 then encode as Emojis.

@holtwick
Copy link
Owner

Do you have sample code for this (emojis) ?

Besides that, Is the general approach sufficient for verification, in your opinion?

@llebout
Copy link
Author

llebout commented Jun 19, 2020

@holtwick

Yes, if a strong enough visual indicator is used.

Basic algorithm:

  • Index all emojis that exist in an array and that are a common base in most Emoji fonts right now that you keep forever to get consistent representations
  • Convert the SHA256 hash to a number of base of the total number of emojis in that array
  • Take that number and while number modulo base is greater than 1
    • Append emoji at index of the previous expression
    • Divide the number by base and assign the result to the number itself

If the Emoji sequence is too long you can display a shorter version by truncating and taking only 6 emojis at the end for example, and allow people to see the full emoji sequence when they hover the Emojis area.

@holtwick
Copy link
Owner

holtwick commented Jun 19, 2020

Ok, I improved it a bit, but will not use Emojis. Changes are:

  • SHA256 of room name and fingerprints
  • 9 char long Base32 of that digest, taken from the beginning (9 * 5 bits = 45 bits)
  • separated in 3 char packages for simple reading

Everything longer would upset people. I can update showing the full data on demand in a later iteration.

CleanShot 2020-06-19 at 14 15 57@2x

See stage.brie.fi

@llebout
Copy link
Author

llebout commented Jun 19, 2020

@holtwick

Emojis are short, they do not upset people. Riot and Matrix uses Emojis for key verification for example.

45 bits of security is not enough and trivial to generate keys for.

Do not put convenience before security, security first, and then convenience. Especially if you are designing a so-called "security first" software. If you don't do it seriously it's nothing more than a lie as a marketing ploy.

Text like this is arguably harder to read than Emojis.

There's this library for example: https://github.com/pfrazee/base-emoji

But the encoding is very much unoptimized, things can be encoded in much smaller amount of emojis. For the most optimized version you can try the algorithm I described in the previous message.

@holtwick
Copy link
Owner

Can you show me an example of the emojis being used for verification?

How many bits would you consider enough?

I wrote some text of the status quo: https://github.com/holtwick/briefing/wiki/Security-Discussion

@holtwick
Copy link
Owner

There's this library for example: https://github.com/pfrazee/base-emoji

Awesome, thanks. The beaker browser guy :)

@llebout
Copy link
Author

llebout commented Jun 19, 2020

@holtwick

128-bit could be acceptable, but offer opportunity to display both the truncated version and the full one (when hovering for example).

Some people are discussing the matter here:

https://security.stackexchange.com/questions/72673/how-bad-is-it-to-truncate-a-hash

One of the answers says that if truncation happens, it has to happen from the leftmost bits. And they share other details about whether or not it is secure. In general, it's not secure, it weakens the security. That's why I think a shorter version can be displayed with the full version available when hovering the area. Users who want to make absolutely sure can verify the full version. But probably if they want to be absolutely sure they wouldnt use a web service at all, unless you've got an extension and sign releases.

@holtwick
Copy link
Owner

Ok, I'll remove the claim of E2EE on prominent places, although I think it is sufficiently solved. The focus of the app is probably more on simplicity and openness. New claim "Direct secure group video chat"

@holtwick
Copy link
Owner

@leo-lb Thanks for your time and help. I learned a lot in the process.

@llebout
Copy link
Author

llebout commented Jun 19, 2020

@holtwick

I think you can do it while keeping it relatively simple for the user! I'll implement the Emoji encoding algorithm and contribute it whenever possible.

Security and convenience are not incompatible!

I am also thankful to you for fully considering the issue.

If you want to remove the claim of end to end encryption fully, it makes sense to modify the README from:

"Briefing instead sends data from peer to peer directly ("Mesh") and is therefore end-to-end encrypted by default by WebRTC implementations."

to

"Briefing instead sends data from peer to peer directly ("Mesh") and therefore the data does not reach the server under normal operation. The WebRTC peers however still trusts the signaling server for the authenticity of the peer-to-peer communications encryption in place. A weak visual indicator is provided to verify the authenticity with an eye sight but these indicators are not strong enough to protect against a motivated attacker. Moreover, the web server fully controls the website's source code and all the security measures in place, it is therefore not viable to rely on these mechanisms to distrust an hosted instance of the Briefing server software."

This was referenced Jun 19, 2020
@holtwick
Copy link
Owner

Ok, that makes sense. I changed it accordingly.

On hover you now also see the full checksum, otherwise only 4 letters for a quick comparison and to get nudged tat

It is all online now. And advertised here https://twitter.com/apperdeck/status/1274000949221240833

@llebout
Copy link
Author

llebout commented Jun 19, 2020

@holtwick

Awesome! Now there is a gap between what's possible to achieve technically for maximum convenience and the currently choosen solution, but I think that can be improved, I'll peak in ASAP.

If you show the full fingerprint on hover, then, the description can be:

"Briefing instead sends data from peer to peer directly ("Mesh") and therefore the data does not reach the server under normal operation. The WebRTC peers however still trusts the signaling server for the authenticity of the peer-to-peer communications encryption in place. A weak visual indicator is provided to verify the authenticity with an eye sight but these indicators are not strong enough to protect against a motivated attacker. A strong visual indicator can be obtained by hovering on the weak visual indicator for solid guarantees. However, the web server fully controls the website's source code and all the security measures in place, it is therefore not viable to rely on these mechanisms to distrust an hosted instance of the Briefing server software. It will be less expensive for an attacker to compromise the hosted instance of the Briefing server software rather than try to crack the encryption."

For that last point:

"It will be less expensive for an attacker to compromise the hosted instance of the Briefing server software rather than try to crack the encryption."

You can mitigate it using: https://github.com/tasn/webext-signed-pages

When that is done correctly, you can restore the end-to-end encryption claims, because in that case they're valid.

The extension requires tedious manual configuration but users who want such level of security should be able to either do that or use a local version of Briefing with Gtk Webkit or Electron (does it exist?). You can sign all Briefing releases with your PGP key and all instances (including third party instances that are not yours) can be verified.

The last point, that is entirely from a usability and practical security perspective (how likely are users to make use of the feature in good conditions):

And then all there's to do is increase the convience of the strong indicator and increase the security of the weak indicator while keeping the convience.

@llebout
Copy link
Author

llebout commented Jun 19, 2020

As an additional note, the hovering is not working right for me, I have a bigger screen size and it's showing the full version even when I'm not hovering the weak indicator. The position where it triggers the strong indicator seems off.

@holtwick
Copy link
Owner

You can mitigate it using: https://github.com/tasn/webext-signed-pages

This is very interesting and seems to be a good idea. But the solution seems to be quite unpopular yet and it needs a lot of user interaction. Also would the user need to get the correct public keys and I guess they can't get them from a keyserver automatically. So you say checking for HTTPS fingerprints is not enough?

@llebout
Copy link
Author

llebout commented Jun 20, 2020

@holtwick

The point is preventing selective overrides of the served source code. If you sign software releases, then someone who compromises your server will not be able to replace the source code for all users or a specific user without alerting them as well. The users can't distrust you completely, that's not possible. The question remains with third party instances, they can also be vetted by this signature.

The extension is not great from a user friendliness point of view. It requires technical expertise.

The ideal situation would be:

  • Ability to detect any new signature emitted for a release, so that if you were to sign a secret release to serve to a specific user because you want to spy on them, it would become known publicly (akin to certificate transparency).
  • Ability to approve or deny updates to a new version
  • Ability to fetch keys from the server instance the first time, and store it forever (TOFU, Trust On First Use)
  • Make the browser extension a soft requirement for using the web application
  • Refuse to load and display a warning when signature does not match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working documentation Improvements or additions to documentation security signaling
Projects
None yet
Development

No branches or pull requests

2 participants