We are thrilled to announce end-to-end encryption across Pusher Channels. With our new end-to-end encryption feature, you can add end-to-end encryption to your application with one line in your server configuration!
April 2020 Update: End-to-end encryption is now officially out of beta, click here for more info.
Messages you send via Pusher Channels have always been encrypted in transit to and from Pusher. But until recently, there wasn’t end-to-end encryption. With our new end-to-end encryption feature, you can add end-to-end encryption to your application with one line in your server configuration!
This means you can prevent Pusher from reading all sensitive content (such as medical or financial data).
Let’s implement end-to-end encryption in that “doctor’s office” app. In this example, we have a web app for your users (doctors), and a server written in PHP.
Our end-to-end encryption feature is implemented on a new channel type, which begins with private-encrypted-
. For example, the doctor with ID 42 in your system might have the channel private-encrypted-dr-42
. When your server learns of a new appointment request, it will trigger an event on that encrypted channel:
1$pusher->trigger( 2 'private-encrypted-dr-' . $_POST['doctor-id'], // an encrypted channel 3 'appointment-request', 4 array("patient-id" => $_POST['patient-id'], "category" => $_POST['category']) 5);
Notice that the body of this event contains sensitive health information: the “category” of the appointment, such as “anxiety”. But by switching to private-encrypted-
, Pusher is unable to see this information, because the $pusher->trigger
function will encrypt the body. To do so, the $pusher
object needs a master key. You provide this master key when initializing the library:
1$pusher = new Pusher\Pusher( 2 getenv('CHANNELS_APP_KEY'), 3 getenv('CHANNELS_APP_SECRET'), 4 getenv('CHANNELS_APP_ID'), 5 array( 6 'cluster' => getenv('CHANNELS_APP_CLUSTER'), 7 'useTLS' => true, 8 'encryption_master_key' => '2tPOaZOZJlQZQhdj4D8kgIhjGfYGcj9i' 9 ) 10);
Above, we use the master key 2tPOaZOZJlQZQhdj4D8kgIhjGfYGcj9i
. You must generate this master key yourself. You can use the openssl
tool for this:
1$ openssl rand -base64 24 22tPOaZOZJlQZQhdj4D8kgIhjGfYGcj9i
If you view the debug console for your dashboard when you trigger an event, you should see an encrypted payload:
Now for the other side: decrypting. Happily, there is nothing to do here: pusher-js automatically decrypts the event body on private-encrypted-
channels!
For each encrypted channel, there is a shared secret between your server and the subscribers to that channel. This channel shared secret is used by the server to encrypt a message to that channel, and by each subscriber to decrypt the message when received.
The channel shared secret is provided to subscribers in the response to an auth endpoint request. This requires no changes to your auth endpoint code:
1// This will include the channel shared secret automatically 2echo $pusher->socket_auth('private-encrypted-dr-42', $socket_id);
The channel shared secret is derived by the SDK from the channel name and your master key. This means that your server does not have to keep track of a large number of shared secrets. For more details, this series of slides shows the rationale behind the design:
Our implementation of end-to-end encryption provides the key property that Pusher cannot read or forge your messages. However, there are some properties that this does not provide:
End-to-end encryption is in beta! It’s currently implemented in most SDKs. See our documentation to try it out! If you would like to see support in more SDKs, or for any other suggestions or advice, please contact us at support@pusher.com.