Data Security Overview
PubNub is serious about the security of your data. Using TLS and AES256 encryption algorithms, and with HIPAA, GDPR, SOC2 type 2, and CCPA compliance, you can be sure your data is safeguarded.
There are several ways in which PubNub helps to secure your app:
- Connection security secures the traffic between your client and PubNub
- Message encryption provides end-to-end security for every message, in transit and at rest
- File encryption provides end-to-end security for every file you upload, in transit and at rest
- Access management provides a detailed permission schema for your app
User ID / UUID
User ID is also referred to as UUID
/uuid
in some APIs and server responses but holds the value of the userId
parameter you set during initialization.
Connection Security
PubNub offers connection level security through TLS Encryption (Transport Layer Security). It's enabled by default and generally there is no reason to disable it for any production application.
Configuring TLS
TLS is enabled by default. If you need to disable it for any reason, it can be done during the PubNub object initialization.
SSL
Some PubNub SDKs, the parameter name is ssl
(a legacy name for TLS) but it represents the latest connection encryption technology available. SSL v3 was deprecated due to a security exploit that was discovered and TLS was developed to replace it as the industry standard. Many will refer to TLS as SSL out of habit.
- JavaScript
- Swift
- Objective-C
- Android
- C#
- Python
var pubnub = new PubNub({
subscribeKey: "mySubscribeKey",
publishKey: "myPublishKey",
userId: "myUniqueUserId",
ssl: false // default 'true'
});
let config = PubNubConfiguration(
publishKey: "demo",
subscribeKey: "demo",
userId: "myUniqueUserId",
useSecureConnections: false // default true
)
let pubnub = PubNub(configuration: config)
PNConfiguration *pnconfig = [PNConfiguration configurationWithPublishKey:@"myPublishKey"
subscribeKey:@"mySubscribeKey"];
pnconfig.uuid = "theClientUUID"
pnconfig.TLSEnabled = NO; // default YES
self.client = [PubNub clientWithConfiguration:pnconfig];
PNConfiguration pnConfiguration = new PNConfiguration();
pnConfiguration.setSubscribeKey("my_subkey");
pnConfiguration.setPublishKey("my_pubkey");
pnConfiguration.setSecure(false); // default true
pnConfiguration.setUserId(new UserId("myUniqueUserId"));
PubNub pubnub = new PubNub(pnconfig);
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"));
pnConfiguration.PublishKey = "myPublishKey";
pnConfiguration.SubscribeKey = "mySubscribeKey";
pnConfiguration.Secure = false; // default true
Pubnub pubnub = new Pubnub(pnConfiguration);
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
pnconfig = PNConfiguration()
pnconfig.publish_key = "myPublishKey"
pnconfig.subscribe_key = "mySubscribeKey"
pnconfig.user_id = "myUserID"
pnconfig.ssl = False # default True
pubnub = PubNub(pnconfig)
TCP Connection Troubleshooting
If you need to capture the TCP traffic (a tcpdump to a .pcap file) to analyze and debug the network traffic, you may need to disable TLS in your development environment. This level of analysis is only necessary to troubleshoot the most difficult network connection and communication issues that are typically outside of the PubNub domain.
Message Encryption
To ensure the highest levels of message security, TLS should be used in combination with message level encryption using AES (Advanced Encryption Standard) that provides symmetric encryption to guarantee end-to-end data security. Message level encryption is required where the data is highly sensitive or where there are compliance requirements like HIPAA or SOC-2.
PubNub SDKs offer built-in AES 256-bit encryption (CBC block cipher mode).
Encrypting Messages
You need to provide a cipher key to encrypt (and decrypt) messages. Message encryption is performed for all messages in all channels for a given API Key.
- JavaScript
- Swift
- Objective-C
- Android
var pubnub = new PubNub({
publishKey: "myPublishKey",
subscribeKey: "mySubscribeKey",
userId: "theClientUserId",
cipherKey: "myCipherKey"
});
var pnconfig = PubNubConfiguration(
publishKey: "myPublishKey",
subscribeKey: "mySubscribeKey",
userId: "myUniqueUserId"
)
pnconfig.cipherKey: "myCipherKey"
var pubnub = PubNub(configuration: pnconfig)
PNConfiguration *pnconfig = [PNConfiguration configurationWithPublishKey:@"myPublishKey"
subscribeKey:@"mySubscribeKey"];
pnconfig.uuid = @"theClientUUID";
pnconfig.cipherKey = @"myCipherKey";
self.pubnub = [PubNub clientWithConfiguration:pnconfig];
PNConfiguration pnconfig = new PNConfiguration();
pnconfig.setPublishKey("myPublishKey");
pnconfig.setSubscribeKey("mySubscribeKey");
pnConfiguration.setUserId(new UserId("myUniqueUserId"));
pnconfig.setCipherKey(myCipherKey);
PubNub pubnub = new PubNub(pnconfig);
The raw message never leaves a trusted authority providing for full circle data encryption. It's encrypted at the time of publish by the PubNub SDK before it's sent and it remains encrypted as it's routed through the PubNub Network till it reaches the client that subscribes to it. The subscribing client will need to decrypt it using the same cipher key. All data that is persisted in Message Persistence (and logging systems) is encrypted and can't be decrypted by anyone unless they hold the required cipher key.
Protect your cipher key
You shouldn't share the cipher key outside of the PubNub network.
Partial Message Encryption
Fully automated message encryption sounds great but it can get in the way of functionality that you may require. Specially, if you're using Mobile Push Notifications, PubNub will not be able to read the mobile push keys and values that you provide in your message payload since it's encrypted. In such cases, you need to encrypt only the sensitive data in your message payload while leaving other pieces of data as clear text.
APNs Example
Let's use an example message payload to demonstrate the proper way to do precise and necessary message data encryption specific to an APNs payload.
Before encryption:
{
"pn_apns": {
"aps": {
"alert": "Your test results are available.",
"sound" : "bingbong.aiff"
}
},
"results": {
"test_name": "pregnancy",
"results": "positive",
"notes": "You are having twins!"
}
}
Encrypt it:
In the above message payload, the only data that really must be encrypted is the results
object. Everything else can remain as plain text.
- JavaScript
- Swift
- Objective-C
- Android
const cipherKey = "pubnubrealtimecommunicationplatf";
const clearText = JSON.stringify(
{"test_name":"pregnancy","results":"positive","notes":"You are having twins!"});
const secureText = pubnub.encrypt(clearText, cipherKey);
let crypto = Crypto(key: "pubnubrealtimecommunicationplatf")
let clearData =
{"test_name":"pregnancy","results":"positive","notes":"You are having twins!"}
let secureText = crypto?.encrypt(plaintext: clearData).get()
NSString *cipherKey = @"pubnubrealtimecommunicationplatf";
NSData *clearData =
@{@"test_name":@"pregnancy",@"results":@"positive",@"notes":@"You are having twins!"}
*clearData = [clearData dataUsingEncoding:NSUTF8StringEncoding];
NSString *secureText = [PNAES encrypt:clearData withKey:cipherKey];
JsonObject clearData = new JsonObject();
clearData.addProperty("test_name", "pregnancy");
clearData.addProperty("results", "positive");
clearData.addProperty("notes", "You are having twins!");
String cipherKey = "pubnubrealtimecommunicationplatf";
String secureText = pubnub.encrypt(clearData.toString(), cipherKey);
The secureData
variable can now be added to the payload. So that PubNub and third party mobile push vendors can process the Push payload correctly.
Using a cipher key, pubnubrealtimecommunicationplatf
in this example (your cipher key will be more complex but exactly 32 chars is required for 256 AES cipher keys), to encrypt only the confidential data, the resulting message payload would be as follows.
After encryption:
{
"pn_apns": {
"aps": {
"alert": "Your test results are available.",
"sound" : "bingbong.aiff"
}
},
"results": "Nio2At2uvQzteLoSqznLkZQ3dlFlMzLGlUwbsMndZ7/7tllq2joJw6WcUv3XpMdEugYRnoEvsrlhEVkSnBibxaxDDWMFEDvKS+VLlA8mfmg="
}
Partial Message Encryption
You may need to encrypt certain data values within the APNs/FCM payload, but be sure not to encrypt any APNs/FCM keys, or any values that need to be parsed as unencrypted text by those mobile push services.
Decrypting Messages
On the message receiver side, your client must also have the same cipher key to use the decrypt
API on the encrypted parts of the message payload.
- JavaScript
- Swift
- Objective-C
- Android
const cipherKey = "pubnubrealtimecommunicationplatf";
// parse the received message and pass the encrypted parts to decrypt API.
// you may use an *iterator* operator to do this on your message
const secureText =
"Nio2At2uvQzteLoSqznLkZQ3dlFlMzLGlUwbsMndZ7/7tllq2joJw6WcUv3XpMdEugYRnoEvsrlhEVkSnBibxaxDDWMFEDvKS+VLlA8mfmg="
const clearData = pubnub.decrypt(secureText, cipherKey);
let crypto = Crypto(key: "pubnubrealtimecommunicationplatf")
// parse the received message and pass the encrypted parts to decrypt API
// you may use an *iterator* operator to do this on your message
let secureText =
"Nio2At2uvQzteLoSqznLkZQ3dlFlMzLGlUwbsMndZ7/7tllq2joJw6WcUv3XpMdEugYRnoEvsrlhEVkSnBibxaxDDWMFEDvKS+VLlA8mfmg="
let clearData = crypto?.decrypt(secureData: secureText).get()
NSString *cipherKey = @"pubnubrealtimecommunicationplatf";
// parse the received message and pass the encrypted parts to decrypt API
// you may use an *iterator* operator to do this on your message
NSString *secureText =
"Nio2At2uvQzteLoSqznLkZQ3dlFlMzLGlUwbsMndZ7/7tllq2joJw6WcUv3XpMdEugYRnoEvsrlhEVkSnBibxaxDDWMFEDvKS+VLlA8mfmg="
NSString *clearData = [PNAES decrypt:secureText withKey:cipherKey];
String cipherKey = "pubnubrealtimecommunicationplatf";
// parse the received message and pass the encrypted parts to decrypt API.
// you may use an *iterator* operator to do this on your message
String secureText =
"Nio2At2uvQzteLoSqznLkZQ3dlFlMzLGlUwbsMndZ7/7tllq2joJw6WcUv3XpMdEugYRnoEvsrlhEVkSnBibxaxDDWMFEDvKS+VLlA8mfmg="
JsonObject clearData = JSON.parse(pubnub.decrypt(cipherKey, secureText));
JsonReader jsonReader = Json.createReader(new StringReader(clearData));
clearData = jsonReader.readObject();
jsonReader.close();
File Encryption
Much like messages, you can also encrypt the files sent from your clients using a cipherKey.
If you specified a cipherKey in the configuration, you don't have to explicitly specify it in the method to encrypt or decypt the uploaded files. If you do pass a cipherKey in the sendFile
or downloadFile
methods, that key takes precedence over the cipherKey you provided in the configuration. Refer to Encrypting Messages for information on how to provide a cipherKey in the configuration.
With client-side encryption, the SDK encrypts file data before it's uploaded to the storage service. The receiving client must decrypt the data upon download using the same key before it's displayed in the end-user application.
Distribution of Keys
While the PubNub SDKs provide methods for encryption and decryption, they do not provide the ability to distribute cipher keys. It's your responsibility to manage and securely distribute and rotate keys for your clients.
Encrypting Files
You can provide a cipherKey in the sendFile
method to encrypt a file or you can use a cipherKey you provided in the configuration. The following example shows how to encrypt a file with a cipherKey you provide in the method body.
- Node.js
- C#
- Go
- Objective-C
- Android
import fs from 'fs';
const myFile = fs.readFileSync('./cat_picture.jpg');
const result = await pubnub.sendFile({
channel: 'my_channel',
message: 'Look at this photo!',
file: { data: myFile, name: 'cat_picture.jpg', mimeType: 'application/json' },
cipherKey: 'my_cipher_key',
});
PNResult<PNFileUploadResult> fileUploadResponse = await pubnub.SendFile()
.Channel("my_channel")
.File("cat_picture.jpg") //checks the bin folder if no path is provided
.CipherKey("my_cipher_key")
.Message("Look at this photo!")
.ExecuteAsync();
PNFileUploadResult fileUploadResult = fileUploadResponse.Result;
PNStatus fileUploadStatus = fileUploadResponse.Status; // contains troubleshooting info
if (!fileUploadStatus.Error && fileUploadResult != null) // checks if successful
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileUploadResult));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileUploadStatus));
show all 16 linesfile, err := os.Open("cat_picture.jpg")
defer file.Close()
if err != nil {
panic(err)
}
resSendFile, statusSendFile, errSendFile := pn.SendFile().
Channel("my_channel").
Message("Look at this photo!").
CipherKey("my_cipher_key").
Name("cat_picture.jpg").
File(file).Execute()
fmt.Println(resSendFile, statusSendFile, errSendFile)
fmt.Println(resSendFile.Data.ID)
NSURL *localFileURL = ...;
PNSendFileRequest *request = [PNSendFileRequest requestWithChannel:@"my_channel"
fileURL:localFileURL];
request.cipherKey = @"my_cipher_key";
[self.client sendFileWithRequest:request completion:^(PNSendFileStatus *status) {
if (!status.isError) {
/**
* File upload successfully completed.
* Uploaded file information is available here:
* status.data.fileIdentifier is the unique file identifier
* status.data.fileName is the name used to store the file
*/
} else {
/**
show all 23 linespubnub.sendFile()
.channel("my_channel"
.fileName("cat_picture.jpg")
.inputStream(inputStream)
.cipherKey("my_cipher_key")
.message("Look at this photo!")
.async(new PNCallback<PNFileUploadResult>() {
@Override
public void onResponse(PNFileUploadResult result, PNStatus status) {
if (!status.isError()) {
System.out.println("send timetoken: " + result.getTimetoken());
System.out.println("send status: " + result.getStatus());
System.out.println("send fileId: " + result.getFile().getId());
System.out.println("send fileName: " + result.getFile().getName());
}
show all 18 linesKey Priority
The cipherKey you provide in the body of the method takes precedence over the cipherKey you provide in the configuration.
Decrypting Files
You must provide a cipherKey in the downloadFile
method to decrypt a file or you can use a cipherKey you provided in the configuration. The following example shows how to decrypt a file with a cipherKey you provide in the method body.
- Node.js
- C#
- Go
- Objective-C
- Android
const file = await pubnub.downloadFile({
channel: 'my_channel',
id: 'd9515cb7-48a7-41a4-9284-f4bf331bc770',
name: 'cat_picture.jpg',
cipherKey: 'my_cipher_key',
});
PNResult<PNDownloadFileResult> fileDownloadResponse = await pubnub.DownloadFile()
.Channel("my_channel")
.FileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.FileName("cat_picture.jpg")
.CipherKey("my_cipher_key")
.ExecuteAsync();
PNDownloadFileResult fileDownloadResult = fileDownloadResponse.Result;
PNStatus fileDownloadStatus = fileDownloadResponse.Status;
if (fileDownloadResult != null)
{
fileDownloadResult.SaveFileToLocal(downloadUrlFileName); //saves to bin folder if no path is provided
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileDownloadResult.FileName));
}
else
{
show all 17 linesresDLFile, statusDLFile, errDLFile := pn.DownloadFile().
Channel("my_channel").
CipherKey("my_cipher_key").
ID("d9515cb7-48a7-41a4-9284-f4bf331bc770").
Name("cat_picture.jpg").Execute()
if resDLFile != nil {
filepathOutput := "cat_picture.jpg"
out, _ := os.Create(filepathOutput)
_, err := io.Copy(out, resDLFile.File)
if err != nil {
fmt.Println(err)
}
}
PNDownloadFileRequest *request = [PNDownloadFileRequest requestWithChannel:@"my_channel"
identifier:@"<file-identifier>"
name:@"cat_picture.jpg"];
request.targetURL = ...;
request.cipherKey = @"my_cipher_key";
[self.client downloadFileWithRequest:request
completion:^(PNDownloadFileResult *result, PNErrorStatus *status) {
if (!status.isError) {
/**
* File successfully has been downloaded.
* status.data.location - location where downloaded file can be found
* status.data.temporary - whether file has been downloaded to temporary storage and
* will be removed on completion block return.
*/
show all 24 linespubnub.getFile()
.channel("my_channel")
.fileName("cat_picture.jpg")
.fileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.cipherKey("my_cipher_key")
.async(new PNCallback<PNDownloadFileResult>() {
@Override
public void onResponse(PNDownloadFileResult result, PNStatus status) {
if (!status.isError()) {
System.out.println("getFile fileName: " + result.getFileName());
System.out.println("getFile byteStream: " + result.getByteStream());
}
System.out.println("getFile status code: " + status.getStatusCode());
}
});
Key Priority
The cipherKey you provide in the body of the method takes precedence over the cipherKey you provide in the configuration.