Back to Home

How to safely store and use secret data in R / Infopulse Ukraine Blog

R

How to safely store and use secret data in R

Original author: Andrie de Vries
  • Transfer
  • Tutorial
From time to time the question arises of how to safely store the username and password in R without setting this data explicitly in your script. I think there are several possible solutions. You can store your parameters:
  1. Directly in the script.
  2. In the file inside the folder with the project that you are not showing.
  3. In the .Rprofile file.
  4. In the .Renviron file.
  5. In json file.
  6. In the safe vault that you are accessing from R.
  7. Using the digest package.
  8. Using the sodium package.
  9. Using the secure package.

Let's look at the main idea, advantages (or disadvantages) of each approach.
[From a translator: in order of increasing utility.]

Directly in the script


The first approach is to store your parameters directly in the script.
id <- "my login name"
pw <- "my password"
call_service(id, pw, ...)

Despite its simplicity, no one seriously offers to do this because of an obvious drawback: you cannot show your code without also showing these parameters.

In the file inside the folder with the project that you are not showing


The second option is implemented almost as easily. The idea is this: you put your parameters in a separate file inside the same folder with the project, for example, “keys.R”. Then you can read the settings, using, for example, source(). Then we exclude “keys.R” from the version control system. If you use git, you can add “keys.R” to your .gitignore settings.

The disadvantage is that you can still accidentally show this file if you are not careful enough.
# keys.R
id <- "my login name"
pw <- "my password"
# script.R
source("keys.R")
call_service(id, pw, ...)

In the .Rprofile file


The third option is to store the parameters in one of the .Rprofile files. This option is quite popular because:
You can store data in another folder, i.e. not in the project folder. Therefore, it is less likely that you accidentally open access to the file.

In .Rprofile, you can write regular R code.
# ~/.Rprofile
id <- "my login name"
pw <- "my password"
# script.R
# id и pw определены в скрипте через .Rprofile
call_service(id, pw, ...)

One of the disadvantages of object definitions "id", and "pw"in .Rprofile - they become part of the global environment. Once there, they are easy to change from a script. For example, using rm()it to clean the global environment will delete them.

A slightly more flexible version of the same method is to use .Rprofile as well, but declare your parameters as environment variables. You can use to set environment variables Sys.setenv(), for reading - Sys.getenv().
# ~/.Rprofile
Sys.setenv(id = "my login name")
Sys.setenv(pw = "my password")
# script.R
# id и pw определены в скрипте через .Rprofile
call_service(id = Sys.getenv("id"), pw = Sys.getenv("pw"), ...)

In the .Renviron file


R also has a mechanism for defining environment variables in a special external file, .Renviron. Working with .Renviron is similar to .Rprofile. The main difference is that .Renviron can set variables directly, without use Sys.setenv().

Environment variables are language independent.
# ~/.Renviron
id = "my login name"
pw = "my password"
# script.R
# id и pw определены в скрипте через .Renviron
call_service(id = Sys.getenv("id"), pw = Sys.getenv("pw"), ...)

In json or yaml file


The json format is mainly used for interacting through web services. Therefore, most modern languages ​​easily interpret json files. The same applies to yaml files. If you want to store parameters in a format that other languages ​​understand, like Python, json might be a good solution.
# keys.json
{
  "id":["my login name"],
  "pw":["my password"]
} 
# script.R
library(jsonlite)
call_service(id = fromJSON("keys.json")$id, 
             pw = fromJSON("keys.json")$pw, ...)

In the safe vault that you are accessing from R


One big drawback of all previous approaches is that in all cases the parameters are stored in unencrypted form somewhere on the disk. Perhaps you are using some kind of tool like keychain or LastPass .

You can use an encrypted drive for storage . Once it is mounted, its contents can be handled like plain text. Those. from user R’s point of view, sensitive data is simply stored as “plain text” somewhere on an encrypted drive.

Using the digest package


Another alternative is to use the digest package , which is supported by Dirk Eddelbuettel. Stefan Doyen proposed this solution:
  1. I use digest package with AES encryption.
  2. I use two functions: one writes files encrypted by AES, the second reads and decrypts these files. These functions are on github .
  3. Then I use the digest package to generate a key to decrypt and encrypt files.
  4. Once all this is ready, I create a data block (dataframe) with a username and password.
  5. I use a function write.aes()to write a parameter locally to an encrypted file.
  6. read.aes() allows you to decrypt the parameters and import them into R.

Thus, secret data does not appear explicitly or in code. This gives an additional opportunity - to store the parameters somewhere else (remote server, usb-disk, etc.). Also, this solution does not require a password every time.

Stefan offers this code to illustrate:
source("crypt.R")
load("key.RData")
credentials <- data.frame(login = "foo", password = "bar", stringsAsFactors = FALSE)
write.aes(df = credentials, filename = "credentials.txt",key = key)
rm(credentials)
credentials <- read.aes(filename = "credentials.txt",key = key)
print(credentials)

Using the sodium package


Another option is to use the sodium package created by Jeroen Oms. The sodium package is an R wrapper for the libsodium cryptographic library .

Wrapper for libsodium: a modern, easy-to-use library for encrypting, decrypting, signing, hashing passwords, etc. Sodium uses curve25519, the latest Diffie-Hellman feature from Daniel Bernstein, which became very popular after the Dual EC DRBG vulnerability was discovered in the NSA.

This means that sodium can be used to set up secure communications, including using asymmetric keys, directly from R. To use sodium to encrypt your data, use the approach described above for digest.

Using the secure package


Finally, the final option is to use the secure package written by Headley Wickham. From the package description:

The secure package provides secure storage in a publicly accessible repository. This allows you to store sensitive data in a public repository so that it is available only to selected users. This is especially useful for testing, because using the package you can store personal data in a public repository without showing them to the whole world.

Secure is based on asymmetric encryption (with public and private keys). Secure generates a random master key and uses it to encrypt (AES256) each file invault/. The master key is not stored anywhere in unencrypted form, instead, a copy encrypted with its public key is stored for each user. Each user can decrypt the master key using his private key, and then use it to decrypt each file.


In order to understand how this works, a whole study may be required. But in general, the idea is this:
  • Secret data is stored in the repository using a key consisting of the public keys of all the people you want to give the right to decrypt.
  • You can use the public key available to every user on github.
  • You can also use the Travis public key if continuous integration is used.

Headley provides step-by-step instructions for using the package in his github repository .

Read Next