Skip to main content
Inspiring
July 8, 2024
Answered

Question about localStorage.setItem(Key, Value) in extension

  • July 8, 2024
  • 2 replies
  • 1413 views

I wanted to ask how safe is to keep data inside localStorage.setItem(Key, Value).

If I want to create extension for Illustrator and want to store license key for that extension inside localStorage. License key in localStorage will be encrypted of course.

Is this safe to do such thing?

This topic has been closed for replies.
Correct answer Inventsable

It depends on what "safe" means. If you're including API keys to paid services then no, storing them in any local file or localStorage is not good practice and is very insecure even if encrypted, but if by "safe" you're asking if a malicious actor could harm the user in any way if they could access and decrypt your license key the short answer is no. At most, all that would happen is a lazily cracked version of your extension might be available online -- but if I wanted to do that, I'd just strip out the code in your extension that checks for licensing to begin with then resign and redistribute it as a ZXP to skip the licensing part entirely and unfortunately, no amount of security measures would prevent that due to how relaxed CEP is with self-signed certificates.

 

If I were a malicious actor looking to redistribute your extension with extra code that modifies the user filesystem then your manner of licensing is completely irrelevant regardless of the depth of your security measures from code visibility alone. All it would take is someone who knows what they're doing committing to the time and effort it would take to just erase whatever lines of code you're using to authenticate a license or make requests to bypass this issue, and though it's not an inevitably that's going to happen, taking too many steps trying to prevent it will end up being a sunken cost in my opinion. Either they have the skill (and you can't stop them anyway) or they don't, and either something like this will happen or it won't. Have decent SEO to appear above any redistribution on search engine results and that catches 99% of potential users finding that redistributed version to begin with. As someone who's made a variety of CEP extensions some of which for large clients with a combined userbase of over 20K licenses, it's never happened to mine, at least that I know of.

 

There are plenty of online resources about "API key provisioning" (exact phrase for ease of googling for you) that address and discuss this along with best practices for security, but it becomes a manner of scale and if I'm honest, I don't think any CEP extension merits the college education level of knowledge needed for perfect security. The Goldilocks Zone between simple and secure is something like this:

 

  • A handshake with an external broker like AWS Secrets Manager under a whitelisted domain/source, or in your case a License Manager with a very similar flow using "forward secrecy" concepts (key exchanges are based on temporary keys which lead to a sensitive key) -- your extension is the whitelisted source, the key is stored externally on the server of the manager, extension makes a request with some manner of token, if that request is validated correctly the manager sends the license key in request response, your extension now knows it's legitimately licensed via response. You'd be storing tokens in localStorage instead of license keys directly and can set these to expire after arbitrary lengths, but details on tokens themselves / how to generate or validate would depend on the specific manager or platform.
  • Using Proof Key for Code Exchange (PKCE) or equivalent in requests that require API access with paid rates when possible.

 

In my opinion, any obstacle is enough to discourage 90%. SHA-256 with some hidden salt could be plenty to store your license in localStorage since most likely will never get beyond that point. If it's your first extension or your first serious extension, it's hard not to have ideas like this -- "I want to prevent people from stealing my work", "I don't want to miss out on any paying customers" -- and so on, but the market is small and niche. Your target market are professional artists who are used to paying for SaaS solutions and other means of improving their production. Focusing too much on things like this can just be a distraction from a worried and anxious inner mind and in reality, won't make much meaningful difference unless your extension is successful enough to sell several hundreds or thousands of licenses to begin with. If the extension isn't 100% done in every other aspect, then there's more pressing work to attend to.

2 replies

Inventsable
InventsableCorrect answer
Legend
July 20, 2024

It depends on what "safe" means. If you're including API keys to paid services then no, storing them in any local file or localStorage is not good practice and is very insecure even if encrypted, but if by "safe" you're asking if a malicious actor could harm the user in any way if they could access and decrypt your license key the short answer is no. At most, all that would happen is a lazily cracked version of your extension might be available online -- but if I wanted to do that, I'd just strip out the code in your extension that checks for licensing to begin with then resign and redistribute it as a ZXP to skip the licensing part entirely and unfortunately, no amount of security measures would prevent that due to how relaxed CEP is with self-signed certificates.

 

If I were a malicious actor looking to redistribute your extension with extra code that modifies the user filesystem then your manner of licensing is completely irrelevant regardless of the depth of your security measures from code visibility alone. All it would take is someone who knows what they're doing committing to the time and effort it would take to just erase whatever lines of code you're using to authenticate a license or make requests to bypass this issue, and though it's not an inevitably that's going to happen, taking too many steps trying to prevent it will end up being a sunken cost in my opinion. Either they have the skill (and you can't stop them anyway) or they don't, and either something like this will happen or it won't. Have decent SEO to appear above any redistribution on search engine results and that catches 99% of potential users finding that redistributed version to begin with. As someone who's made a variety of CEP extensions some of which for large clients with a combined userbase of over 20K licenses, it's never happened to mine, at least that I know of.

 

There are plenty of online resources about "API key provisioning" (exact phrase for ease of googling for you) that address and discuss this along with best practices for security, but it becomes a manner of scale and if I'm honest, I don't think any CEP extension merits the college education level of knowledge needed for perfect security. The Goldilocks Zone between simple and secure is something like this:

 

  • A handshake with an external broker like AWS Secrets Manager under a whitelisted domain/source, or in your case a License Manager with a very similar flow using "forward secrecy" concepts (key exchanges are based on temporary keys which lead to a sensitive key) -- your extension is the whitelisted source, the key is stored externally on the server of the manager, extension makes a request with some manner of token, if that request is validated correctly the manager sends the license key in request response, your extension now knows it's legitimately licensed via response. You'd be storing tokens in localStorage instead of license keys directly and can set these to expire after arbitrary lengths, but details on tokens themselves / how to generate or validate would depend on the specific manager or platform.
  • Using Proof Key for Code Exchange (PKCE) or equivalent in requests that require API access with paid rates when possible.

 

In my opinion, any obstacle is enough to discourage 90%. SHA-256 with some hidden salt could be plenty to store your license in localStorage since most likely will never get beyond that point. If it's your first extension or your first serious extension, it's hard not to have ideas like this -- "I want to prevent people from stealing my work", "I don't want to miss out on any paying customers" -- and so on, but the market is small and niche. Your target market are professional artists who are used to paying for SaaS solutions and other means of improving their production. Focusing too much on things like this can just be a distraction from a worried and anxious inner mind and in reality, won't make much meaningful difference unless your extension is successful enough to sell several hundreds or thousands of licenses to begin with. If the extension isn't 100% done in every other aspect, then there's more pressing work to attend to.

Inspiring
July 25, 2024

@Inventsable Thank you for such detailed answer. I will select this as corect answer as I want to award for your time and for useful informations.

 

But I have one more question. It will be gumroad for license keys and unfortonelly store licence key locally.

Now, if for example I choose to store inside some file, license key and machine Id.

Lets say that this machine Id will protect against reuse this file on multiple computers, by simple coping file.

But still it will be possible to reuse this file in same computer, in the way that someone could just copy that file, do deactivation (which will be offer in extensions ui) and then just paste back that file.

What is the best protection against this?  

Inventsable
Legend
July 26, 2024

If I were doing it, I'd use fs.stat or fs.statsync to know when it was last modified:

 

// Use fs and path from node
const fs = require("fs");
const path = require("path");

// Resolve the filepath to absolute
const filePath = path.resolve("./somePathHere.json");

// Get the millisecond value of when the file was last modified:
const dateModified = fs.statSync(filePath).mtime.getTime();

 

If you're the one writing the file, write a key/value to localstorage with Date.now() at the same time your license file was written or whenever your panel is modifying it, then when the panel mounts in future compare if your localstorage value is equal to the license file stat getTime above within a small margin like ~20 ms (or just capture the getTime of the file after writing it for exact comparison). If it is equal you'll know that it was last modified by you, but if it isn't, the user (or something else) must have modified it.

Inspiring
July 12, 2024

If someone enables debug mode, they will then be able to modify the script to do whatever they want, including access to all localStorage values.

Inspiring
July 19, 2024

Yes but data will be encrypted.

Alternative is to store in some file but there also will be the case that data are accessible, but if they are encrypted we are on the same.

What is difference?