If you run a command in Terminal, say
rsync -avuP [SourcPath] [DestPath]
That command will get logged in, say .bash_history, .zsh_history, .bash_sessions, etc.
So if you make use of something as notoriously insecure as sshpass
say sshpass -P password -p MySecetPassword [Some command requiring std input], that too will be logged.
But what happens when you do the equivalent when spawning a process using Node JS?
passw = functionThatRetrievesPasswordSecurely();
terminalCmd = "sshpass";
terminalArgs = ["-P, "password", "-p", passw, "command", "requiring", "a", "password", "entry"];
spawn = require("child_process").spawn(terminalCmd, terminalArgs);
spawn.stdout.on("data", data => {console.log("stdout, no details"});
spawn.stderr.on("data", data => {console.log("stderr, no details"});
spawn.on("close", data => {console.log("Process complete, no details"});
Are the terminalCmd or terminalArgs logged anywhere?
If so, where?
If not, is this a secure way to make use opf sshpass?
There isn't a node specific history file for execs unless you created one by logging the arguments. There can be lower level OS logging that captures this type of data, like an audit log.
Passing a password on the command line is still considered the least secure way.
Try -f to pass a file or -d for a file descriptor instead (or ssh keys should always be the first port of call)
The man page explains...
The -p option should be considered the least secure of all of sshpass's options. All system users can see the password in the command line with a simple "ps" command. Sshpass makes a minimal attempt to hide the password, but such attempts are doomed to create race conditions without actually solving the problem. Users of sshpass are encouraged to use one of the other password passing techniques, which are all more secure.
In particular, people writing programs that are meant to communicate the password programatically are encouraged to use an anonymous pipe and pass the pipe's reading end to sshpass using the -d option.
I have a script that takes windows compatible passwords and uses them to create an account for the user on the computer with that as their system password.
I have run into an issue where if I escape them and pass it to create the account it is taken literally. Single ' and double " quotes are allowed in windows.
Example user enters hello'world
escaped as hello\'world and stored in the database as hello\'world.
user inputs hello'world login.
Computer expects hello\'world as the correct password, user can not login.
Adding code:
echo "somepass" | sudo -S /Applications/Setup\ user.app/Contents/Resources/nugget "Joe User" "juser" "ju$er'Pa$$".345"
Essentially the account for the user is created, another admin account has to be used and the password set from the gui where ju$er'Pa$$".345 is entered and from there the user can login fine.
Does this do what you want? (Obviously you need a safe method to retrieve the password, either from read input or by reading from a file handle or pipe).
neech#nicolaw.uk:~ $ read -r password ; printf '%q\n' "$password"
ju$er'Pa$$".345
ju\$er\'Pa\$\$\".345
neech#nicolaw.uk:~ $
I am trying to figure out how to make a shell script that will generate new users, a randomly generated password using openssl rand -base64 12, UID, GID, Any description, and the Home directory for the users in chronological order then pipe to new users in a different command with correct syntax.
To make it simple I need to run the script using the standard input from the command newusers for the first user then generate the other 4 users by adding 1 seen below. The output will be something similar to:
user01:generatedpassword:1001:1001:Description:/home/user01:/bin/bash
user02:generatedpassword:1002:1002:Description:/home/user02:/bin/bash
user03:generatedpassword:1003:1003:Description:/home/user03:/bin/bash
user04:generatedpassword:1004:1004:Description:/home/user04:/bin/bash
user05:generatedpassword:1005:1005:Description:/home/user05:/bin/bash
I'm a little confused by what you mean but you should add a variation of the following lines to your script:
useradd usr01
and then
password=`openssl rand -base64 12`
echo $password | passwd --stdin usr01
This will mean you can see the password and it just doesn't assign it to the usr01 without you knowing what it is.
I am working in a Dockerfile but there is a "secure" MariaDB server script I need to run which is interactive and I don't know how to deal with this.
Basically this is the flow I have follow on the script at test environment and is the same I want to achieve in the Dockerfile without user interaction by just answering as you seen on the flow below:
# /usr/bin/mysql_secure_installation
Enter current password for root (enter for none): [ENTER] // because there is no password
OK, successfully used password, moving on...
Set root password? [Y/n] n
... skipping.
Remove anonymous users? [Y/n] Y
... Success!
Disallow root login remotely? [Y/n] n
... skipping.
Remove test database and access to it? [Y/n] Y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] Y
... Success!
Cleaning up...
So I need to write a bash script or something else that could handle this automatically but has not idea, how would you take care of this?
I think you can try with two different approaches:
Use expect script eventually "evaluated" from bash. Man page here
Or:
Use "here document" syntax from a bash script (no expect)
** EDIT - Example of option 2 **
#!/bin/bash
...
/usr/bin/mysql_secure_installation <<EOF
n
Y
n
Y
Y
EOF
...
basically you pass all your answers to the standard input of your mysql_secure_installation.
Using expect is just a little bit more complicated. You can start from here
Another option, mysql_secure_installation is a simple bash script that executes several mysql commands, just use the sql commands.
DELETE FROM mysql.user WHERE User='';
DROP DATABASE test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
save this commands in a file and pipe it to mysql
mysql < my_file.sql
Usually I connect to a database with R using JDBC/ODBC driver. A typical code would look like
library(RJDBC)
vDriver = JDBC(driverClass="com.vertica.jdbc.Driver", classPath="/home/Drivers/vertica-jdbc-7.0.1-0.jar")
vertica = dbConnect(vDriver, "jdbc:vertica://servername:5433/db", "username", "password")
I would like others to access the db using my credentials but I want to protect my username and password. So I plan save the above script as a "Connections.r" file and ask users to source this file.
source("/opt/mount1/Connections.r")
If I give execute only permission to Connections.r others cannot source the file
chmod 710 Connections.r
Only if I give read and execute permission R lets users to source it. If I give the read permission my credentials will be exposed. Is there anyways we could solve this by protecting user credentials?
Unless you were to deeply obfuscate your credentials by making an Rcpp function or package that does the initial JDBC connection (which won't be trivial) one of your only lighter obfuscation mechanisms is to store your credentials in a file and have your sourced R script read them from the file, use them in the call and them rm them from the environment right after that call. That will still expose them, but not directly.
One other way, since the users have their own logins to RStudio Server, is to use Hadley's new secure package (a few of us sec folks are running it through it's paces), add the user keys and have your credentials stored encrypted but have your sourced R script auto-decrypt them. You'll still need to do the rm of any variables you use since they'll be part of environment if you don't.
A final way, since you're giving them access to the data anyway, is to use a separate set of credentials (the way you phrased the question it seems you're using your credentials for this) that only work in read-only mode to the databases & tables required for these analyses. That way, it doesn't matter if the creds leak since there's nothing "bad" that can be done with them.
Ultimately, I'm as confused as to why you can't just setup the users with read only permissions on the database side? That's what role-based access controls are for. It's administrative work, but it's absolutely the right thing to do.
Do you want to give someone access, but not have them be able to see your credentials? That's not possible in this case. If my code can read a file, I can see everything in the file.
Make more accounts on the SQL server. Or make one guest account. But you're trying to solve the problem that account management solves.
Have the credentials sent as command arguments? Here's an example of how one would do that:
suppressPackageStartupMessages(library("argparse"))
# create parser object
parser <- ArgumentParser()
# specify our desired options
# by default ArgumentParser will add an help option
parser$add_argument("-v", "--verbose", action="store_true", default=TRUE,
help="Print extra output [default]")
parser$add_argument("-q", "--quietly", action="store_false",
dest="verbose", help="Print little output")
parser$add_argument("-c", "--count", type="integer", default=5,
help="Number of random normals to generate [default %(default)s]",
metavar="number")
parser$add_argument("--generator", default="rnorm",
help = "Function to generate random deviates [default \"%(default)s\"]")
parser$add_argument("--mean", default=0, type="double", help="Mean if generator == \"rnorm\" [default %(default)s]")
parser$add_argument("--sd", default=1, type="double",
metavar="standard deviation",
help="Standard deviation if generator == \"rnorm\" [default %(default)s]")
# get command line options, if help option encountered print help and exit,
# otherwise if options not found on command line then set defaults,
args <- parser$parse_args()
# print some progress messages to stderr if "quietly" wasn't requested
if ( args$verbose ) {
write("writing some verbose output to standard error...\n", stderr())
}
# do some operations based on user input
if( args$generator == "rnorm") {
cat(paste(rnorm(args$count, mean=args$mean, sd=args$sd), collapse="\n"))
} else {
cat(paste(do.call(args$generator, list(args$count)), collapse="\n"))
}
cat("\n")
Sample run (no parameters):
usage: example.R [-h] [-v] [-q] [-c number] [--generator GENERATOR] [--mean MEAN] [--sd standard deviation]
optional arguments:
-h, --help show this help message and exit
-v, --verbose Print extra output [default]
-q, --quietly Print little output
-c number, --count number
Number of random normals to generate [default 5]
--generator GENERATOR
Function to generate random deviates [default "rnorm"]
--mean MEAN Mean if generator == "rnorm" [default 0]
--sd standard deviation
Standard deviation if generator == "rnorm" [default 1]
The package was apparently inspired by the python package of the same name, so looking there may also be useful.
Looking at your code, I'd probably rewrite it as follows:
library(RJDBC)
library(argparse)
args <- ArgumentParser()
args$add_argument('--driver', dest='driver', default="com.vertica.jdbc.Driver")
args$add_argument('--classPath', dest='classPath', default="/home/Drivers/vertica-jdbc-7.0.1-0.jar")
args$add_argument('--url', dest='url', default="jdbc:vertica://servername:5433/db")
args$add_argument('--user', dest='user', default='username')
args$add_argument('--password', dest='password', default='password')
parser <- args$parse_args
vDriver <- JDBC(driverClass=parser$driver, parser$classPath)
vertica <- dbConnect(vDriver, parser$url, parser$user , parser$password)
# continue here
Jana, it seems odd that you are willing to let the users connect via R but not in any other way. How is that obscuring anything from them?
I don't understand why you would not be satisfied with a guest account that has specific SELECT-only access to certain tables (or even views)?