cross-platform private keys storage for nodejs - node.js

Question
I tried to search for a solution, with google and here at StackOverflow, but no success.
What I looking for:
I need API to generate a new keypair, like
//publicKey is either Buffer or string, so I can use it in `createPublicKey` call.
let publicKey = await impl.generate("keypairUniqueName");
Decrypt some data with key by key name
let decryptedBuffer = await impl.decrypt("keypairUniqueName", encryptedBuffer);
sign data with private key
let signatureBuffer = await impl.sign("keypairUniqueName", rawDataBuffer);
delete key by unique name
await impl.deleteKeypair("keypairUniqueName");
keys storage should be scoped to specific device, local user account, and (my) app, and ideally, with some other string parameter like in-app account or profile id, so I can call on Electron installation:
let implHive = await ImplFactory.ensureForKeysHive();
and later on adding local user record:
let impl = await implHive.createKeystore(userAccountId, localPinCode);
and on login:
let impl = await implHive.openKeystore(userAccountId, localPinCode);
ideal requirement: I should be able to do it at Windows desktop, Linux desktop, Android, iOS. Most likely context is Electron App or nodejs based CLI.
I understand I can save an encrypted files to paths like ~/.appName/keystore/userId.slot, but I need to be sure this file can not be used on other device if copied to other device with ctrl+c - ctrl+v or cp command. So for file-based impl anyway question comes where to save password or other device-scoped encryption data or device-specific keypair to make sure only my app can use that device-scoped keypair.
Does the safeStorage of electron is what I looking for regarding per-device and per platform user as way to store something that only and instance of my app on same machine can save and load?
From documentation I understood electron 's safeStorage is specific to user, not to device-user-app intersection.
In this regard I can implement something like larger password model, where account-specific key of my app stored as original password with some app-specific salt added, like
//example purposes-only
let fullAppSpecificKeysVaultPassword = "vendor-alias/my-app/account_${localPinCode}_${purposeCode}";
inside storage represented by safeStorage provided electron, but I not sure is this strategy good enough, or may be there some npm package or electron API I overlooked?
It is important that local keys vault for the app under question should be usable across installations/deinstallations/re-installations/upgrades of same app.
Is something like that exists with exact features?
All this resembles very much the Android Keystore - https://developer.android.com/training/articles/keystore#WhichShouldIUse
Especially per-app scoping.
But it is unclear is there something like that to be used in cross-platform manner by an electron and/or nodejs app.
Context, goals, Purpose, and Why
For self-education purposes I thinking about making some small app with 2 features:
public keys mapping to user aliases, random device ids and optional readable device aliases, with small profiles like name, avatar, and 1 sentence user-self description, may be more fields in profiles eventually - limited variation of keybase, with federation like Mastodon, but with rule to keep keys catalogue in sync across federation relays when joining to "relays federation" to make sure profiles intact if relay server who created them gone offline or left keys federation, or relays not available, and only profiles cached by clients are available. I find it interesting to make in context of keybase being eaten by Zoom.
end-to-end encrypted chat app that would work in environments like LAN, WiFi, and Bluetooth, and other local networking to be used both with internet and when standard internet access not available. You may say that such projects are exists already like Serval or Thali or some other, and yeah, I was inspired by them to some extent.
So, self-education aspect, and question like How much of that can I do myself using only Electron or nodejs? are main motivations behind this idea.

Related

is electron's `safeStorage` for passwords and login credentials?

I need to store login credentials with electron js because it doesnt save them like all browsers. I have seen a lot of questions like this, but I never found a solution. I have seen in the electron docs about the safeStorage feature. is the it safe enough/good enough to store login credentials on the client side? if not what other tools are available to do that? I have heard about keytar but is it good?
The safeStorage api in electron exposes OS-level encryption/decryption using current user's secret key - please refer to electron source and chromium's os_crypt. On windows it utilizes DPAPI while on *nixes it uses whatever password manager the OS has as the documentation suggested.
is the it safe enough/good enough to store login credentials on the client side?
Depends, you should define "secure" first.
Ask yourself, should the same user allowed to read whatever value inside the encrypted text? A tech-literate person might write his own tools to decrypt things you store using that API you are out of luck. See this QA for further discussion.
if not what other tools are available to do that?
There are a lot of tools (and encryption algorithm) to encrypt stuff in nodejs. However, you have to remember an encryption require you to have a key of some sort and the key need to be protected too. Hence, try your best to avoid egg-chicken problem with your key of keys.
OS-based key storage avoids the key of keys problem by storing the "master key" in a way that only accessible using its API. At runtime, you can't retrieve the key at all, you just send a set of bytes for the OS to magically encrypt/decrypt. While at rest, the OS may rely on secure storage such as TPM (Trusted Platform Module).
is electron's safeStorage for passwords and login credentials?
Depends, if you are running a web service it is preferrable to not doing so. You should never dump end user's user name/password directly on a storage that you can't guarantee its safety by yourself (e.g. your server). You should, put an identifier which can be revoked or may expire at later date - token or cookies.
Imagine the trouble when your end user device get stolen. If it's a token/cookie, they can request you to revoke their access from that device - similar to "Log me out from all other device."
However, if its an in-situ application that authenticates to itself then its a fair game - though keep in mind about the first point. Its all down to your security model.

Obfuscate string/program in Go [duplicate]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Most app developers will integrate some third party libraries into their apps. If it's to access a service, such as Dropbox or YouTube, or for logging crashes. The number of third party libraries and services is staggering. Most of those libraries and services are integrated by somehow authenticating with the service, most of the time, this happens through an API key. For security purposes, services usually generate a public and private, often also referred to as secret, key. Unfortunately, in order to connect to the services, this private key must be used to authenticate and hence, probably be part of the application.
Needless to say, that this faces in immense security problem. Public and private API keys can be extracted from APKs in a matter of minutes and can easily be automated.
Assuming I have something similar to this, how can I protect the secret key:
public class DropboxService {
private final static String APP_KEY = "jk433g34hg3";
private final static String APP_SECRET = "987dwdqwdqw90";
private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;
// SOME MORE CODE HERE
}
What is in your opinion the best and most secure way to store the private key? Obfuscation, encryption, what do you think?
As it is, your compiled application contains the key strings, but also the constant names APP_KEY and APP_SECRET. Extracting keys from such self-documenting code is trivial, for instance with the standard Android tool dx.
You can apply ProGuard. It will leave the key strings untouched, but it will remove the constant names. It will also rename classes and methods with short, meaningless names, where ever possible. Extracting the keys then takes some more time, for figuring out which string serves which purpose.
Note that setting up ProGuard shouldn't be as difficult as you fear. To begin with, you only need to enable ProGuard, as documented in project.properties. If there are any problems with third-party libraries, you may need to suppress some warnings and/or prevent them from being obfuscated, in proguard-project.txt. For instance:
-dontwarn com.dropbox.**
-keep class com.dropbox.** { *; }
This is a brute-force approach; you can refine such configuration once the processed application works.
You can obfuscate the strings manually in your code, for instance with a Base64 encoding or preferably with something more complicated; maybe even native code. A hacker will then have to statically reverse-engineer your encoding or dynamically intercept the decoding in the proper place.
You can apply a commercial obfuscator, like ProGuard's specialized sibling DexGuard. It can additionally encrypt/obfuscate the strings and classes for you. Extracting the keys then takes even more time and expertise.
You might be able to run parts of your application on your own server. If you can keep the keys there, they are safe.
In the end, it's an economic trade-off that you have to make: how important are the keys, how much time or software can you afford, how sophisticated are the hackers who are interested in the keys, how much time will they want to spend, how much worth is a delay before the keys are hacked, on what scale will any successful hackers distribute the keys, etc. Small pieces of information like keys are more difficult to protect than entire applications. Intrinsically, nothing on the client-side is unbreakable, but you can certainly raise the bar.
(I am the developer of ProGuard and DexGuard)
Few ideas, in my opinion only first one gives some guarantee:
Keep your secrets on some server on internet, and when needed just grab them and use. If user is about to use dropbox then nothing stops you from making request to your site and get your secret key.
Put your secrets in jni code, add some variable code to make your libraries bigger and more difficult to decompile. You might also split key string in few parts and keep them in various places.
use obfuscator, also put in code hashed secret and later on unhash it when needed to use.
Put your secret key as last pixels of one of your image in assets. Then when needed read it in your code. Obfuscating your code should help hide code that will read it.
If you want to have a quick look at how easy it is to read you apk code then grab APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
Another approach is to not have the secret on the device in the first place! See Mobile API Security Techniques (especially part 3).
Using the time honored tradition of indirection, share the secret between your API endpoint and an app authentication service.
When your client wants to make an API call, it asks the app auth service to authenticate it (using strong remote attestation techniques), and it receives a time limited (usually JWT) token signed by the secret.
The token is sent with each API call where the endpoint can verify its signature before acting on the request.
The actual secret is never present on the device; in fact, the app never has any idea if it is valid or not, it juts requests authentication and passes on the resulting token. As a nice benefit from indirection, if you ever want to change the secret, you can do so without requiring users to update their installed apps.
So if you want to protect your secret, not having it in your app in the first place is a pretty good way to go.
Old unsecured way:
Follow 3 simple steps to secure the API/Secret key (Old answer)
We can use Gradle to secure the API key or Secret key.
1. gradle.properties (Project properties): Create variable with key.
GoogleAPIKey = "Your API/Secret Key"
2. build.gradle (Module: app) : Set variable in build.gradle to access it in activity or fragment. Add below code to buildTypes {}.
buildTypes.each {
it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}
3. Access it in Activity/Fragment by app's BuildConfig:
BuildConfig.GoogleSecAPIKEY
Update:
The above solution is helpful in the open-source project to commit over Git. (Thanks to David Rawson and riyaz-ali for your comment).
As per Matthew and Pablo Cegarra's comments, the above way is not secure and Decompiler will allow someone to view the BuildConfig with our secret keys.
Solution:
We can use NDK to Secure API Keys. We can store keys in the native C/C++ class and access them in our Java classes.
Please follow this blog to secure API keys using NDK.
A follow-up on how to store tokens securely in Android
Adding to #Manohar Reddy solution, firebase Database or firebase RemoteConfig (with Null default value) can be used:
Cipher your keys
Store it in firebase database
Get it during App startup or whenever required
decipher keys and use it
What is different in this solution?
no credintials for firebase
firebase access is protected so only app with signed certificate have
privilege to make API calls
ciphering/deciphering to prevent middle man interception. However
calls already https to firebase
The App-Secret key should be kept private - but when releasing the app
they can be reversed by some guys.
for those guys it will not hide, lock the either the ProGuard the code. It is a refactor and some payed obfuscators are inserting a few bitwise operators to get back the jk433g34hg3
String. You can make 5 -15 min longer the hacking if you work 3 days :)
Best way is to keep it as it is, imho.
Even if you store at server side( your PC ) the key can be hacked and printed out. Maybe this takes the longest? Anyhow it is a matter of few minutes or a few hours in best case.
A normal user will not decompile your code.
One possible solution is to encode the data in your app and use decoding at runtime (when you want to use that data). I also recommend to use progaurd to make it hard to read and understand the decompiled source code of your app . for example I put a encoded key in the app and then used a decode method in my app to decode my secret keys at runtime:
// "the real string is: "mypassword" ";
//encoded 2 times with an algorithm or you can encode with other algorithms too
public String getClientSecret() {
return Utils.decode(Utils
.decode("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}
Decompiled source code of a proguarded app is this:
public String c()
{
return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}
At least it's complicated enough for me. this is the way I do when I have no choice but store a value in my application. Of course we all know It's not the best way but it works for me.
/**
* #param input
* #return decoded string
*/
public static String decode(String input) {
// Receiving side
String text = "";
try {
byte[] data = Decoder.decode(input);
text = new String(data, "UTF-8");
return text;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "Error";
}
Decompiled version:
public static String a(String paramString)
{
try
{
str = new String(a.a(paramString), "UTF-8");
return str;
}
catch (UnsupportedEncodingException localUnsupportedEncodingException)
{
while (true)
{
localUnsupportedEncodingException.printStackTrace();
String str = "Error";
}
}
}
and you can find so many encryptor classes with a little search in google.
This example has a number of different aspects to it. I will mention a couple of points that I don't think have been explicitly covered elsewhere.
Protecting the secret in transit
The first thing to note is that accessing the dropbox API using their app authentication mechanism requires you to transmit your key and secret. The connection is HTTPS which means that you can't intercept the traffic without knowing the TLS certificate. This is to prevent a person intercepting and reading the packets on their journey from the mobile device to the server. For normal users it is a really good way of ensuring the privacy of their traffic.
What it is not good at, is preventing a malicious person downloading the app and inspecting the traffic. It is really easy to use a man-in-the-middle proxy for all traffic into and out of a mobile device. It would require no disassembly or reverse engineering of code to extract the app key and secret in this case due to the nature of the Dropbox API.
You could do pinning which checks that the TLS certificate you receive from the server is the one you expect. This adds a check to the client and makes it more difficult to intercept the traffic. This would make it harder to inspect the traffic in flight, but the pinning check happens in the client, so it would likely still be possible to disable the pinning test. It does make it harder though.
Protecting the secret at rest
As a first step, using something like proguard will help to make it less obvious where any secrets are held. You could also use the NDK to store the key and secret and send requests directly, which would greatly reduce the number of people with the appropriate skills to extract the information. Further obfuscation can be achieved by not storing the values directly in memory for any length of time, you can encrypt them and decrypt them just before use as suggested by another answer.
More advanced options
If you are now paranoid about putting the secret anywhere in your app, and you have time and money to invest in more comprehensive solutions, then you might consider storing the credentials on your servers (presuming you have any). This would increase the latency of any calls to the API, as it will have to communicate via your server, and might increase the costs of running your service due to increased data throughput.
You then have to decide how best to communicate with your servers to ensure they are protected. This is important to prevent all of the same problems coming up again with your internal API. The best rule of thumb I can give is to not transmit any secret directly because of the man-in-the-middle threat. Instead you can sign the traffic using your secret and verify the integrity of any requests that come to your server. One standard way of doing this is to compute an HMAC of the message keyed on a secret. I work at a company that has a security product that also operates in this field which is why this sort of stuff interests me. In fact, here is a blog article from one of my colleagues that goes over most of this.
How much should I do?
With any security advice like this you need to make a cost/benefit decision about how hard you want to make it for someone to break in. If you are a bank protecting millions of customers your budget is totally different to someone supporting an app in their spare time. It is virtually impossible to prevent someone from breaking your security, but in practice few people need all of the bells and whistles and with some basic precautions you can get a long way.
Whatever you do to secure your secret keys is not going to be a real solution. If developer can decompile the application there is no way to secure the key, hiding the key is just security by obscurity and so is code obfuscation. Problem with securing a secret key is that in order to secure it you have to use another key and that key needs to also be secured. Think of a key hidden in a box that is locked with a key. You place a box inside a room and lock the room. You are left with another key to secure. And that key is still going to be hardcoded inside your application.
So unless the user enters a PIN or a phrase there is no way to hide the key. But to do that you would have to have a scheme for managing PINs happening out of band, which means through a different channel. Certainly not practical for securing keys for services like Google APIs.
The most secure solution is to keep your keys on a server and route all requests needing that key through your server. That way the key never leaves your server, so as long as your server is secure then so is your key. Of course there is a performance cost with this solution.
The only true way to keep these private is to keep them on your server, and have the app send whatever it is to the server, and the server interacts with Dropbox. That way you NEVER distribute your private key in any format.
Ages old post, but still good enough. I think hiding it in an .so library would be great, using NDK and C++ of course. .so files can be viewed in a hex editor, but good luck decompiling that :P
Keep the secret in firebase database and get from it when app starts ,
It is far better than calling a web service .

Securing a login system without passwords

I'm developing a mobile application for a company. Everyone at the company has an #company.com email address. The app itself is confidential, so it will only be installed on employees' devices. This app communicates with an external server to store and retrieve data.
Ideally what I would like to accomplish is to let people log in to the app by just providing their email address, without a password. Here is my current thinking:
A new user opens the app for the first time on a certain device and puts in their email address. The email address is sent to the server, along with a static token embedded in the application (which is the same for all instances of the application).
The server verifies the token and the fact that the email address is #company.com. It responds with a new token/key for use only with that user and device, which the client stores in plain text locally. That key is effectively the user's password. It is hashed, stored in the server database, and marked as disabled.
There are two possibilities at this point:
The server sends an email to that address confirming that they want to log in on a new device. The email contains a link which, when clicked, marks the key as enabled. There would need to be rate-limiting on new device requests so people can't get spammed if someone discovers the token embedded in the app.
An administrator specifically approves new device requests.
Every subsequent client request to the server must include the key.
Assuming all communication is over SSL, does this sound like a secure strategy? Is there a more secure or simpler approach?
Additionally, what is the best way to generate the token that will be stored client-side? Since I want users to only put in their email address the first time they use the app, I believe that this token will never change. Here is my current algorithm (PHP) loosely based on Drupal's drupal_get_token():
// Usage: get_token($email) or get_token($client_token)
function get_token($value = '') {
$salt = hash('sha256', 'Some static, predefined phrase');
$hmac = base64_encode(hash_hmac('sha256', $email, $salt, TRUE));
return $hmac;
}
As you can see it doesn't protect against parallel attacks (e.g. if someone figured out the predefined phrase and algorithm and they had access to the database, they could generate hashes and compare them against the ones stored in the database) but because the original key value is already long I don't think this would be nearly as effective as it would be against normal passwords. Additionally I am not sure of a way to create a dynamic salt that an attacker would not already have access to if they could access the database (or honestly if it would even matter at that point, since getting access to the database would expose the data we're trying to keep confidential anyway).
After some research and more thought, I believe that the answer to this question comes down to the vulnerability of the local storage. Since it's safe to assume in this case that only company employees will be using the app, there is insignificant risk of malicious code running in it even if there was a problem in the code that would make that possible. As a result the main risk is from some other app taking advantage of a security hole in the OS's local storage implementation to read the local private key off the disk. Since the existence of the app should not be known to anyone outside the company, it is very unlikely that this information would be directly targeted. So I think this is an acceptable process for this company.
In the general case though, anyone considering implementing a similar model should be aware of the risks of basically storing a password in plain text locally. (This is as opposed to storing a password in the user's head, or equally likely in plain text in a password file elsewhere on their machine; it's your call which is more secure.)

Commonly used solutions for credential caching?

I have question about credential caching in applications. I've searched around on the net for solutions to this problem, but I haven't found anything (which is really surprising, since this is something that every Facebook, Twitter, and email client application has to deal with).
My question is this:
Let's say I'm building some simple Twitter client. I don't want to force the user to enter their password every time. How do most applications tackle this problem? At some point, the client needs to make an API call to authenticate (which includes the password, which is usually in plain text). However, saving the password in plain text somewhere not the correct solution, obviously. So, how do most apps do this safely? I suppose you could cache the password in a file or db if the password is encrypted, but then how do you safely store the decryption key? Or is it generated at runtime using unique information from the client machine as a seed?
Are there any resources (articles, books, etc.) that talk about this? How do most apps handle this?
Thanks!
Single-sign-on (SSO) setups accomplish what you describe typically by providing centralized methods to generate, distribute and validate a key using some type of session ID.
See for one method (used by StackExchange/StackOverflow):
http://openid.org/
Here's something I didn't know: This category of functionality is known as Federated Identity. For instance, our web system where I work offers (but doesn't require) Shibboleth. See here for a list of options:
http://en.wikipedia.org/wiki/Category:Federated_identity

How to verify an application is the application it says it is?

Here's the situation: we have a common library which can retrieve database connection details from a central configuration store that we have setup. Each application uses this library when working with a database.
Basically, it will call a stored procedure and say "I am {xyz} application, I need to connect o " and it will return the connection details for that applications primary database (server, instance, database, user, and password).
How would one go about locking that down so that only application {xyz} can retrieve the passwords for {xyz} databases (there is a list of database details for each application... i just need to secure the passwords)?
The usual way is to have a different config store per app and give each app a different user/password to connect to the config store.
That doesn't prevent anyone from changing the app and replacing the user/password for app X with the values from app Y but it's a bit more secure, especially when you compile this data in instead of supplying it via a config file.
If you want to be really secure, you must first create a secure connection to the store (so you need a DB drivers that supports this). This connection must be created using a secure key that is unique per application and which can be verified (so no one can just copy them around). You will need to secure the executable with hashes (the app will calculate its own hash somehow and send that to the server who will have a list of valid hashes for each app).
All in all, it's not something trivial which you can just turn on with an obscure option. You will need to learn a lot about security and secure data exchange, first. You'll need a way to safely install your app in an insecure place, verify its integrity, protect the code against debuggers that can be attached at runtime and against it running in the virtual machine, etc.
Off the top of my head, try PKI.
Are you trying to protected yourself from malicous programs, and is this a central database that these applications are connecting to? If so you should probably consider a middle layer between your database and application.
I'm not sure this applies to your case, depending on how what your answers to the abovementioned would be, but by the comments it sounds like you are having a similar case to what this question is about.
Securing your Data Layer in a C# Application
The simplest/most straightforward way would be to store the passwords in encrypted format (storing passwords in plaintext is just plain bad anyhow, as recently demonstrated over at PerlMonks) and make each application responsible for doing its own password encryption/decryption. It would then not matter whether an app retrieved another app's passwords, as it would still be unable to decrypt them.
One possibility is to keep the passwords in the database in an encrypted form, and convey the encryption key to the allowed application(s) in a secure connection.Then, only the application with the encryption key can actually get the passwords and not others.

Resources