Is it ok to store user's secrets in PropertiesService.getUserProperties()?

148 Views Asked by At

I am developing a Google Workspace Addon (standalone script) which will make REST API calls to external service and for that purpose it needs to provide an API key. I request the API key input from a user and then store it in PropertiesService in the following way:

function onSheets(e) {
  const userProperties = PropertiesService.getUserProperties();
  const saved_api_key = userProperties.getProperty('api_key');
  const api_key: string = saved_api_key ? saved_api_key : "";
  const builder = CardService.newCardBuilder();
  const apiKeyInput = CardService.newTextInput().setTitle('API Key')
    .setFieldName('api_key')
    .setHint('Enter your API Key')
    .setValue(api_key);
  const saveApiKey = CardService.newAction().setFunctionName('saveApiKeyFn');
  const button = CardService.newTextButton().setText('Save').setOnClickAction(saveApiKey);
  const optionsSection = CardService.newCardSection()
    .addWidget(apiKeyInput)
    .addWidget(button)


  builder.addSection(optionsSection);
  return builder.build();
}

function saveApiKeyFn(e) {
  const api_key = e.formInput.api_key;
  const userProperties = PropertiesService.getUserProperties();
  userProperties.setProperty('api_key', api_key);

  return CardService.newActionResponseBuilder()
    .setNotification(CardService.newNotification()
      .setText("API Key saved"))
    .build();

}

Since userProperties are scoped to a current user it seems fine. But I have serveral problems with this solution:

  1. Is this really safe? I mean it is stored in plain text so maybe there are ways to retrive it by other mailcious user?
  2. The idea that by mistake I would use getScriptProperties() and thus leak one user's API key to all other users gives me nightmares. It is highly sensitive API key. It would cost a user tons of money if abused.

I read that some user's suggest https://cloud.google.com/secret-manager but I am not sure it's fit for this particular scenario. It would require one more external API call. It is not free. And lastly from what I underestand I would be sort of an owner of all of these secrets since I will be the owner of the Google Cloud project in which this API runs.

All I want is for the users to be able to store their keys safely, so that no one else including me can never access them. What would you suggest? Thanks!

1

There are 1 best solutions below

4
On

Is this really safe? I mean it is stored in plain text so maybe there are ways to retrive it by other mailcious user?

Security is relative. There's no such thing as absolute secrecy. Here are some attack scenarios:

  • Google employees or support may have unrestricted access

  • If a particular user installed a trigger, that trigger runs as that user and other users, if they can trigger the script and have edit access to the script, will be able to access the keys. A common scenario would be a installed edit trigger in a sheet. User B can access user A, if he can make a edit as well as edit the script. As mentioned in the comments by doubleunary, this is less of a problem in a published add on, as the source code is not accessible or editable.

  • Encrypting keys is a possibility. But, where would you store the decrypting key? You could ask every user to have a custom password for decrypting the key. But how many times are you going to make a API call? Would they have to enter the key every time? At what point does convenience overtake the need for secrecy?

The idea that by mistake I would use getScriptProperties() and thus leak one user's API key to all other users gives me nightmares. It is highly sensitive API key. It would cost a user tons of money if abused.

That is a possibility, but one that's easily avoidable by careful code review by yourself and your peers.

Those are the scenarios I could think of.

Related:

Securely Storing API Secrets used in Google Apps Script - Published Library