Reputation: 14768
I just started implementing FCM into my Django backend.
The problem I encountered is the following.
In the docs you are told to generate a private key JSON file and securely store it. Usually I store my keys in an os.env variable. But this is not possible, since this is a whole file and not just a value. Also on the same page, the doc tells you how to get a request token:
def _get_access_token():
"""Retrieve a valid access token that can be used to authorize requests.
:return: Access token.
"""
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'service-account.json', SCOPES)
access_token_info = credentials.get_access_token()
return access_token_info.access_token
As you can see here, the library needs direct access to the file.
So my question is? How do I securely store this? I'm currently hosting on heroku, so I need this in my version control system.
Upvotes: 0
Views: 1184
Reputation: 71
please read the below documentation provided for firebase_admin.credentials.Certificate().
So, you can create a credential Certificate by passing a dict from the parsed key file contents. key file content can come from an encrypted environment variable value. Use this credential to initialize the app.
Upvotes: 1
Reputation: 1060
this is Based on what ivanspenchev suggested in his post.
Flow is : read json data -> encrypt with a key - > decrypt with a key. I am not using his suggested encrypt algo, because I dont like it.
But the basic idea is, that you have a class "EncryptEngine" that does two things, encrypts a string, and decrypts a string.
public class EncryptEngine
{
Cipher ecipher;
Cipher dcipher;
// 8-byte Salt
byte[] salt = {
(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32,
(byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03
};
// Iteration count
int iterationCount = 19;
public EncryptEngine() {
}
/**
*
* @param secretKey Key used to encrypt data
* @param plainText Text input to be encrypted
* @return Returns encrypted text
* @throws java.security.NoSuchAlgorithmException
* @throws java.security.spec.InvalidKeySpecException
* @throws javax.crypto.NoSuchPaddingException
* @throws java.security.InvalidKeyException
* @throws java.security.InvalidAlgorithmParameterException
* @throws java.io.UnsupportedEncodingException
* @throws javax.crypto.IllegalBlockSizeException
* @throws javax.crypto.BadPaddingException
*
*/
public String encrypt(String secretKey, String plainText)
throws NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
UnsupportedEncodingException,
IllegalBlockSizeException,
BadPaddingException {
//Key generation for enc and desc
KeySpec keySpec = new PBEKeySpec(secretKey.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
// Prepare the parameter to the ciphers
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
//Enc process
ecipher = Cipher.getInstance(key.getAlgorithm());
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
String charSet = "UTF-8";
byte[] in = plainText.getBytes(charSet);
byte[] out = ecipher.doFinal(in);
String encStr = new String(Base64.getEncoder().encode(out));
return encStr;
}
/**
* @param secretKey Key used to decrypt data
* @param encryptedText encrypted text input to decrypt
* @return Returns plain text after decryption
* @throws java.security.NoSuchAlgorithmException
* @throws java.security.spec.InvalidKeySpecException
* @throws javax.crypto.NoSuchPaddingException
* @throws java.security.InvalidKeyException
* @throws java.security.InvalidAlgorithmParameterException
* @throws java.io.UnsupportedEncodingException
* @throws javax.crypto.IllegalBlockSizeException
* @throws javax.crypto.BadPaddingException
*/
public String decrypt(String secretKey, String encryptedText)
throws NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
UnsupportedEncodingException,
IllegalBlockSizeException,
BadPaddingException,
IOException {
//Key generation for enc and desc
KeySpec keySpec = new PBEKeySpec(secretKey.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
// Prepare the parameter to the ciphers
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
//Decryption process; same key will be used for decr
dcipher = Cipher.getInstance(key.getAlgorithm());
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
byte[] enc = Base64.getDecoder().decode(encryptedText);
byte[] utf8 = dcipher.doFinal(enc);
String charSet = "UTF-8";
String plainStr = new String(utf8, charSet);
return plainStr;
}
public static void main(String[] args) throws Exception {
EncryptEngine cryptoUtil=new EncryptEngine();
String key="ezeon8547";
JsonFactory f = new JsonFactory();
JsonParser jp =
f.createJsonParser(/MyDocuments/Repo/Myproject/service-account.json);
String plain;
while (jp.nextToken() == JsonToken.START_OBJECT)) {
plain += jp.toString();
}
String enc=cryptoUtil.encrypt(key, plain);
System.out.println("Original text: "+plain);
System.out.println("Encrypted text: "+enc);
String plainAfter=cryptoUtil.decrypt(key, enc);
System.out.println("Original text after decryption: "+plainAfter);
}
}
Upvotes: 2
Reputation: 46
The way we do it:
Encrypt the json string / Store in Resource file Decryption key, stored as Env variable.
When creating the credentials decrypt the encrypted string.
Upvotes: 3
Reputation: 598740
Most teams keep the JSON file out of version control and add to the environment manually.
While not exactly the same as keeping the values in an environment variable, it has similar security. A developer with only access to version control can't access the key, and a developer cannot accidentally run on their own system with the production keys. But on the other hand: someone who has access to the production server, can get the key in both cases.
Upvotes: 1