Hiding secret from command line parameter on Unix

Solution 1:

  1. First, you can NOT hide command line arguments. They will still be visible to other users via ps aux and cat /proc/$YOUR_PROCESS_PID/cmdline at the time of launching the program (before the program has a chance to do run-time changes to arguments). Good news is that you can still have a secret by using alternatives:

  2. Use environment variables (with caveats). If your program can read them, do this:

     mySecret='hello-neo' myCommand
    
  3. Use standard input:

     mySecret='hello-neo' printenv mySecret | myCommand
    
  4. Use a dedicated file if you want to keep the secret detached from the main script (note that you'd be recommended to use full disc encryption and make sure the file has correct chmod permissions):

     cat /my/secret | myCommand
    
  5. Use temporary file descriptor:

     myCommand <( mySecret='hello-neo' printenv mySecret )
    

In the last case your program will be launched like myCommand /dev/fd/67, where the contents of /dev/fd/67 is your secret (hello-neo in this example).


In all of the above approaches, be wary of leaving the command in bash command history (~/.bash_history). You can avoid this by either running the command from a script (file), or by interactively prompting yourself for password each time:

    read -s mySecret && export mySecret
    myCommand  # approach 2
    printenv mySecret | myCommand  # approach 3
    myCommand <( printenv mySecret )  # approach 4

Solution 2:

If the secret doesn't change between executions, use a special configuration file, ".appsecrets". Set the permissions of the file to be read-only by owner. Inside the file set an environment variable to the secret. The file needs to be in the home directory of the user running the command.

#!/bin/bash  
#filename: .appsecrets
set SECRET=polkalover  

Load the config file so the environment variable gets set.

. ~/.appsecrets

What I've seen done:

1)
echo $SECRET | command

works if the command prompts for the password from stdin AND if 'echo' is a builtin of your shell. We were using Korn.

2)
password=$ENV{"SECRET"};

works if you have control of the code (e.g. in perl or C++)

3)
. ./.app.config #sets the environment variables
isql -host [host] -user [user] -password <<SECRET
${SQLPASSWORD}
SECRET

works if the command can accept the secret from std-in. One limitation is that the <<string has to be the last argument given to the command. This might be troublesome if there is a non-optional arg that has to appear after -password

The benefit of this approach is you can arrange it so the secret can be hidden in production. Use the same filename in production but it will be in the home directory of the account that runs the command in production. You can then lock down access to the secret like you would access to the root account. Only certain people can 'su' to the prod account to view or maintain the secret while developers can still run the program because they use their own '.appsecret' file in their home directory.

You can use this approach to store secured information for any number of applications, as long as they use different environment variable names for their secrets.

(WRONG WAY)
One old method I saw the DBAs use was to set SYBASE to "/opt/././././././././././././././././././././././././././././././././././sybase/bin". So their commandlines were so long the ps truncated it. But in linux I think you might be able to sniff out the full commandline from /proc.