Building secure end-to-end webchat with ThemisInformation Security
While developing components of our products, we love to explore use cases and usability through creating real-world test stands.
0fc is a side-product of WebThemis research: while doing some protocol design for front-end clients with WebThemis services, we wanted to try it in a real-world situation. We’ve set ourselves a novel idea: end-to-end encrypted webchat, inclined towards client anonymity, giving zero trust to the server, built only with typical Themisprimitives.
Always seeking real-world testing of any interesting models and ideas we stumble, we’ve created a simple web application for Absolutely Discrete Communications :)
With 0fc, you:
- don’t need client apps (web client app is loaded the first time you connect to host)
- don’t need static keys
- are able to receive temporary invitation key by any channel
- are authenticated only by knowledge of this invitation key, which is being issued by chatroom owner
0fc can run on any Google Chrome browser and here’s how it looks:
This post outlines the process, security model and protocol. It may be of interest for security protocol designers, Themis users looking forward to seeing an example of complicated security process fully covered by Themis and people generally interested in cryptography.
If you don’t feel like reading long blog posts, here’s github repository with a short readme, you may just jump straight to the code.
0fc consists of 2 classical components: client and server.
Clients are responsible for:
- showing UI to the user
- all cryptographic and trust management functions
- communication with relay server
Client code consists of PNaCl module holding all security logic, WebThemis/Themis library and HTML/CSS/JS UI
Server is responsible for:
- serving UI + PEXE (PNaCl module) to clients via HTTP GET
- running WebSocket relay service, which receives messages and relays them to everyone.
Over WebSocket link, clients talk to the server via SecureSession Themis object, which provides high-level transport security. Server keys are hardcoded into clients, so trust is established based on correlation between real server key and server key fed to client in binaries.
Server code is written in Python, with pythemis extension linking to core C code.
Within this SecureSession link, SecureCell-encrypted messages are transmitted.
- Room owner generates a key pair [client]
- Room owner generates room key (which will be used to encrypt messages in the room) [client]
- Room owner requests the server to create the room, receiving room id in response [client]+[server]
Inviting others (key sharing)
- Room owner generates a random (one-time) invite token [client]
- Room owner sends an invite by some out-of-band channel (like email), which includes invite token, his public key and room id [client]
- User receives the invite token [client]
- User generates a key pair [client]
- User generates random joining key [client]
- User sends a secure message to room owner through server with encrypted joining key [client]
- Server may check through ACL whether this invite is valid and pass the message to room owner [server]
- Room owner unwraps joining key [client]
- Room owner sends sealed room key to user through server using joining key as master key and invite token as context [client]
- Server may check through ACL whether this response is valid and pass the message to the user [server]
- User unseals the room key [client]
- User sends confirmation sealed message to the room owner. [client]
- Owner, upon checking users confirmation message signs his public key and sends to server [client]+[server]
- Server checks the signature and considers user as added to the chatroom [server]
- Once invite token been used, it is discarded by the room owner [server]
- Room members exchange messages sealing them with room key. Server just forwards encrypted messages without having access to their contents. [server]
- Keypair is generated for every room [client]
- Keypair is stored in browser persistent storage [client]
- Browser persistent storage is encrypted with Secure Cell (seal mode), key derived from user’s password, inputs when joining the chat [client]
- clients communicate with server using Themis secure session [server]
- server’s trusted public key is hardcoded in the clients [client]
- server does not perform client authentication, automatically trusts every SS client key (this is first obvious step to harden if security is more important than ubiquity and anonymity) [server]
- every 100 (configurable) messages sent and received, room owner generates new key, encrypts it with old key and sends special message [client]
- server enforces such messages may come only from room owner [server]
- a list of members is maintained for every room as a list of public keys (+indication who is room owner) [server]
- every room has a room owner (originally, room creator) [server]
- room owner is responsible for key rotation [client]
- server enables clients to fetch chat history since their last departure for members who have been online and know keys before rotation [server]
- server enables clients to fetch chat history since last key rotation for new members [server]
Most group chat cases have been thoroughly studied by cryptographic community, for most solutions of varying elegance exist.
However, group chat with emphasis on anonymity, zero trust to server and zero server’s intervention into cryptographic / access flow (server only participates in transport security and in encrypted message relay) is quite rare thing.
Assets and targets
Potential attackers could be interested in 3 things:
- read communication contents
- tamper with communication contents
- identify users
Current threat model focuses on:
- securing the communication content
- avoiding content falsification
- without enforcing additional identification/trust requirements towards peers, thus providing some level of anonymity for users inside the system.
However, every possible user should realize that large-scale attackers can partially identify chatroom members by metadata collection and correlation analysis, including traffic analysis.
To be used in totally discrete manner, 0fc requires transport identity protection.
Server and client rely on a number of external components and their security. However:
- server is composed of HTTP stack and websocket stack, both based on asyncio / aiohttp python libraries. Server is given 0 trust; cryptographic layout is composed in a way, in which server can either comply with design and deliver it’s role or deny service. Recording traffic, which is being relayed between clients, doesn’t enable attackers to achieve anything: traffic is SecureCell-encrypted blobs with key rotation.
- client is composed of 3 essential components:
- PNaCl module, composed of 0fc client, WebThemis, which consists of Themis and LibreSSL’s libcrypto built for specific architecture. Vulnerabilities in libcrypto’s crypto algorithm implementation are of limited possibility: all Themis build targets are validated with tests known to work across number of cryptoprimitive’s implementations equally.
- Google Chrome and it’s PNaCl environment may be altered on local client to behave differently, specifically tunnel plaintext input/output from JS<>PNaCl interface; this is outside of scope of current research: Chrome is considered to be trusted environment.
- Web UI: web UI can be a subject to many attacks (XSS/CSRF/), we’ve tried to isolate most in-browser attacks with the maximum simplicity of HTML/CSS stack. Moreover, Chrome is known to put extra effort into each page’s runtime security, yet this remains the weakest link, because JS code talking to PNaCl object is still subject to all web attacks.
Let’s enumerate every possible way external attacker might tamper with code’s logic of execution:
- HTTP server root, which provides HTML/CSS/JS/PEXE to the client has 0 interaction with server code itself. It is completely passive (and could be offloaded to Nginx, apache or virtually any HTTP, when we’ve tested it we served it as static Nginx files).
- WebSocket listener service, which expects legitimate SecureSession traffic and will just reject anything else. More specifically, design of SecureSession is such that only Session initiation messages are accepted from new clients.
- Web UI: by providing malformed input into Web UI, one might try to affect other Web UI’s. This splits into two problems:
- Parsing messages during encryption: design of SecureCell protects WebThemis from buffer overflows and other malicious actions against encryption/decryption code.
- Web UI behavior after decryption: this is considered outside of the scope of current research.
Potential attackers, by attacking the transport layer, could:
- impersonate client
- impersonate server
- intercept traffic
- modify traffic
Client impersonation: valid clients know the key, invalid clients don’t. By impersonating the client (even with valid PEXE from server), attacker only gets to connect to server on transport layer.
Impersonate server: all clients have pre-shared server key in their binaries. If attacker impersonates server, rebuilds client with his keys, and starts serving them instead of trusted server — he’ll just take the relaying load instead of a legitimate machine, and will get no access to the attack targets, e.g. actual data. We’re specifically fond of this feature :)
Intercept traffic: SecureSession is specifically designed to prevent interception and decryption of traffic. However, by intercepting initial HTTP GET / HTTP response attacker is able to identify the IP address of the potential client.
Modify traffic: integrity control of SecureSession prevents traffic from being tampered by an attacker. However, HTTP traffic could be modified, and PEXE/Web UI/etc. could be replaced with malicious code. In most cases it is a DoS attack — client just won’t connect to the server or will not be able to participate in. However, there is a theoretical possibility of cleverly modifying JS code, which could compromise all traffic going to this client. Protecting against integrity attacks on web code is outside of this research’s scope, but they are quite obvious.
For us, 0fc shows a few important things:
- client-side end-to-end security is still complicated and is subject to many risks.
- having a good cross-platform crypto library (like lovely Themis, which we’ve built for ourselves specifically for this case) makes designing such security schemes a much easier effort.
- real-world testing on every stage is what guarantees the satisfactory experience. Many findings outlined in previous WebThemis / PNaCl articles wouldn’t have existed without this pet project of ours.
For you, it might be a useful chunk of code to study ease of Themis usage :) Anyway, take a look yourself.