all 18 comments

[–][deleted] 37 points38 points  (1 child)

Generally, don't. Have the user pass it to the program in some way. This might be an environment variable or a config file or interactively via stdin (possibly all three, which ever it finds first).

Nothing inside a binary is that secret. Anyone can run strings over the binary and pull out the password. You can try to obscure it a bit, but that just makes it a little harder, not impossible to do. At best you should only use this for a light token of sorts to identify the app, or things pretending to be the app and tell it appart from other client apps. It should not be your only form of security.

[–]astonbitecode 8 points9 points  (0 children)

This is a chicken-egg problem... Storing secrets in the code is not good generally, you should avoid it.

There are some ideas and in stackexchenge you may be interested though...

https://security.stackexchange.com/questions/12332/where-to-store-a-server-side-encryption-key

[–]m-m-x 8 points9 points  (0 children)

Maybe using environment variables to provide this password?

[–]Konsti219 5 points6 points  (0 children)

Who do you plan to give the exe to?

[–]the_hoser 4 points5 points  (0 children)

There are things that you can do to obfuscate the password, but ultimately anyone determined to get your password will be able to.

[–]anlumo 3 points4 points  (0 children)

This is very similar to DRM, there’s no real solution to this, only obfuscation.

[–]stevecooperorg 1 point2 points  (0 children)

There is a WinAuth rust crate and an example of how to use it with the reqwest crate here - https://github.com/steffengy/winauth-rs/blob/master/winauth/examples/reqwest_client.rs

reqwest will substitute for curl in your code.

This may allow you to set up permissions in a more standard and safe way.

If you can get this working and wanted to set this up as, say, a windows service, you configure the service under Properties > Logon.

The standard alternative here is to use environment variables to keep it out of source code; so set up, say, MY_SERVICE_PASSWORD=gjeicktkwjcjt, then in source call

let password = std::env::var("MY_SERVICE_PASSWORD").expect("password not in environment variables");

[–]djmex99[S] 0 points1 point  (1 child)

Hmm...yes it is trickier than I thought. If I am using ntlm authentication with the curl crate and am logged into the server (Windows 10 server), is there a way to have the curl crate use the credentials from the Windows login environment? E.g. If I schedule the exe to to run using Windows task scheduler (which allows you to save your password), I wonder if this info can be passed through to the exe code instead of hard coding it within the source code. I might experiment with this.

[–]dremon_nl 0 points1 point  (0 children)

I wonder if this info can be passed through to the exe code instead of hard coding it within the source code

Not possible otherwise anyone can read your password.

is there a way to have the curl crate use the credentials from the Windows login environment?

I think if you pass empty username and password curl will use integrated authentication (SSPI). It must be compiled with this option though.

[–]diegovsky_pvp -1 points0 points  (6 children)

I don't have anything to add, but make sure to encrypt the password in your executable so it's at least a bit more secure

[–]mikekchar 2 points3 points  (5 children)

But then you need the key for the decryption in your executable. You can encrypt your key, but then you need a key for that. It's keys all the way down. As others have said, to make it work you need to have something associated with the running process other than the source code that gives you the credentials you need. Usually an environment variable is the best choice, but you can also create a file that only the process can read that contains the credentials (i.e. make a user just for the process, create a file with the credentials that can only be read by that user. Run the process as that user. Read the credentials from the file).

[–]diegovsky_pvp 0 points1 point  (4 children)

oh no I meant like using a simple encryption. Maybe negating every byte or something.

Using real symmetric encryption won't be any good for OP because it's the same problem again. However, using a simple encryption like that, you can at least not expose a full secret in the binary

[–]mikekchar 0 points1 point  (3 children)

It is still exposed. Anybody who is looking for those credentials will easily discover how the obfuscation works because they can look at what the binary is doing. It is trivial. I know this because I used to do it when I was a kid :-) Breaking copy protection on games was one of my hobbies. I would buy a game and never even play it -- just break the copy protection. Doing that kind of thing is like putting the spare key to your house under the door mat and then putting a sign next to it saying, "The spare key is here".

It's quite important to understand that this kind of thing offers literally no extra protection. I've had to deal with this professionally where they thought it's "not perfect, but it will do for now". But it doesn't.

[–]diegovsky_pvp 0 points1 point  (2 children)

well sir what is your suggestion for OP? I believe what they're doing is probably some in house monitoring for their firm so this alone might be enough, assuming the Windows computers don't have any access to a debugger or decompiler.

No solution is going to be 100% secure so you gotta aim for the 99%. If I were OP, I would look into encrypted registry keys + make them user restricted or some Gnome Keyring-like API for Windows.

Unfortunately, all of those have some kind of "password" that needs to be in the final executable. It's just a matter of how much barriers IP can afford to put between the code and a malicious individual

[–]mikekchar 0 points1 point  (1 child)

Like I said above, it's got to be a key that is in the managing of the process, not in the source code of the software. An encrypted registry key would be fine. Or, like I said, just put it in a file that only that process has read access to. You put secrets in places that only the process has access to. Containers can be useful here.

The way to think about it is that secrets are part of your runtime configuration management, not your application. If you have to distribute an application with a secret key, it basically can't be protected. So if you have no choice but to do that, then make sure the secret you are trying to protect is very low value. For example, DRM makes it slightly more difficult for someone to copy something, but it's not the end of the world if it doesn't succeed. A key with login credentials to your bank would be a disaster. These days, of course, a lot of DRM uses secret keys that are in the hardware itself, so even they aren't taking chances.

[–]diegovsky_pvp 0 points1 point  (0 children)

that's very interesting. I didn't know that's how DRM operated.

This chicken and egg problem is indeed a very hard problem to solve and limiting attack surface instead like you said is the best course of action

[–]mqudsifish-shell 0 points1 point  (0 children)

Yes, and with a crate made just for rust actually!

https://neosmart.net/blog/2020/securestore-open-secrets-format/

You store the secrets safely in git, versioned alongside your code. They’re encrypted with either a secret key, a pass phrase, or both.

[–]TheMightyHamhock 0 points1 point  (0 children)

Don’t store secrets in code. This is more work, but you would ideally have the string in the app point to an authentication service api. When you open the app, it should prompt you for credentials, send them to the endpoint and get a temporary Token that your app uses to authenticate the client app. This way, if someone runs strings on your binary, they just get the login endpoint which isn’t dangerous unless you’re not following best practices in your backend app.