I'm writing a CLI using node and I've arrived at the part where I take user input and append it to a string that is the command for the child_process.exec function.
const CURL_CHILD = exec('npm view --json ' + process.argv[2] + ...
I am trying to figure out what I need to do to process.argv[2] before I pass it to the exec function. I've surfed around for a while and haven't found any questions or answers that address this specific case.
What is the best way to sanitize this user input for this particular use case? What is actually needed here?
Update
I'm still surfing around trying to learn and answer my own question and found this link which suggests I use js-string-escape (a node package). I'd really like to use something native/vanilla to do this. Does node have any tools for this?
Update 2
I finally stumbled upon the buzzwords "command injection" and found a slew of articles recommending the use of child_process.execFile or child_process.spawn. I'm still curious if there is a native way to sanitize the input, while still securing the full shell process created by child_process.exec. I am leaving this open in hopes someone can answer it.
Your user input arguments may contain variable chars that the shell is going to interpret them in its own way. So for instance, in Linux, $ has a special meaning.
If you want to use such argument as-is avoiding the shell interpretation, you have to escape them. The same we do with some special chars in HTML (eg. < and > has special meaning so we use to escape them in HTML like < and respectively >). The same applies here.
So the answer to your question is first to find out the special chars in your shell/environment and escape them.
A good rule of thumb is to escape chars like double-quote ", single-quote ', space , the dollar-sign $ (because it's an Illuminati symbol, right? ;-), the grave-accent ` and obviously the backslash \.
So let's suppose that your command is the one below. To escape it just use some simple regex like this:
cmd = "npm view --json " + process.argv[2];
escapedCmd = cmd.replace(/(["\s'$`\\])/g,'\\$1');
I hope it helps :-)
Try the npm package escape-it. Should work with *nix OSes, but has some support for Windows, too.
Related
Here's the script:
node /app/ganache-core.docker.cli.js — quiet \ — account=”0x873c254263b17925b686f971d7724267710895f1585bb0533db8e693a2af32ff,100000000000000000000" \ — account=”0x8c0ba8fece2e596a9acfc56c6c1bf57b6892df2cf136256dfcb49f6188d67940,100000000000000000000"
I've read What's the magic of "-" (a dash) in command-line parameters?. And I took away that it CAN mean standard input... if the authors of the bash program define it as such.
However, here (link to ganache-core.docker.cli.js github file), I cannot find how or where the author of ganache-core.docker.cli.js would have defined the dash ("-") as standard input. Can someone point that out as well?
Edit: I am looking for confirmation that the dashes do mean standard input for cli args, but more-so looking to understand, WHY they should be definitively be interpreted as stnin when according the linked question above it's only a convention.
Edit2: I suspect the CLI arg parsing library is yArgs
This command line is just badly formatted. You're reading into something that isn't there. Some Blog software author thought it was a smart idea to auto-reformat the article so that hyphens and such were long dashes and quotes were "smart", etc. In the end, somehow a space ended up after the dash, before the next parameter.
For example, let's look at this:
node /app/ganache-core.docker.cli.js — quiet
Even if we assume that's a regular hyphen -, we know it's not supposed to have a space after it. It's supposed to be -quiet. And, if you have any doubt about this, you can read in the source code where this is defined:
.option('q', {
group: 'Other:',
alias: 'quiet',
describe: 'Run ganache quietly (no logs)',
type: 'boolean',
default: false
})
The same is true for -account.
And I took away that it CAN mean standard input... if the authors of the bash program define it as such.
Yes, that's correct. I don't know what this software does, but if it's reading from STDIN, it's not because you told it to on the command line. It's because that's what it does.
I'm looking for a way (other than ".", '.', \.) to use bash (or any other linux shell) while preventing it from parsing parts of command line. The problem seems to be unsolvable
How to interpret special characters in command line argument in C?
In theory, a simple switch would suffice (e.g. -x ... telling that the
string ... won't be interpreted) but it apparently doesn't exist. I wonder whether there is a workaround, hack or idea for solving this problem. The original problem is a script|alias for a program taking youtube URLs (which may contain special characters (&, etc.)) as arguments. This problem is even more difficult: expanding "$1" while preventing shell from interpreting the expanded string -- essentially, expanding "$1" without interpreting its result
Use a here-document:
myprogramm <<'EOF'
https://www.youtube.com/watch?v=oT3mCybbhf0
EOF
If you wrap the starting EOF in single quotes, bash won't interpret any special chars in the here-doc.
Short answer: you can't do it, because the shell parses the command line (and interprets things like "&") before it even gets to the point of deciding your script/alias/whatever is what will be run, let alone the point where your script has any control at all. By the time your script has any influence in the process, it's far too late.
Within a script, though, it's easy to avoid most problems: wrap all variable references in double-quotes. For example, rather than curl -o $outputfile $url you should use curl -o "$outputfile" "$url". This will prevent the shell from applying any parsing to the contents of the variable(s) before they're passed to the command (/other script/whatever).
But when you run the script, you'll always have to quote or escape anything passed on the command line.
Your spec still isn't very clear. As far as I know the problem is you want to completely reinvent how the shell handles arguments. So… you'll have to write your own shell. The basics aren't even that difficult. Here's pseudo-code:
while true:
print prompt
read input
command = (first input)
args = (argparse (rest input))
child_pid = fork()
if child_pid == 0: // We are inside child process
exec(command, args) // See variety of `exec` family functions in posix
else: // We are inside parent process and child_pid is actual child pid
wait(child_pid) // See variety of `wait` family functions in posix
Your question basically boils down to how that "argparse" function is implemented. If it's just an identity function, then you get no expansion at all. Is that what you want?
Until recently, I was under the impression that by convention, all Linux command options were required to be prefixed by a hyphen (-). So for example, the instruction ls –l executes the ls command with the l option (here we can see that the l option is prefixed by a hyphen).
Life was good until I got to the chapter of my Linux for beginners book that explained the ps command. There I learned that I could write something like ps u U xyz where as far as I can tell, theu and U are options that are not required to be prefixed by a hyphen. Normally, I would have expected to have to write that same command as something like ps –uU xyz to force the usage of a hyphen.
I realize that this is probably a stupid question but I was wondering if there is a particular reason as to why the ps command does not follow what I thought was the standard way of specifying command options (prefixing them with hyphens). Why the variation? Is there a particular meaning to specifying hyphen-less options like that?
There are a handful of old programs on Unix that were written when the conventions were not as widely adopted, and ps is one of them. Another example is tar, although it has since been updated to allow options both with and without the - prefix.
IMO the best practice concerning hyphenation is to use them as the default go-to. More times than not, they have accepted hyphen prefixes to most or all flags/options available for commands. Happy to be corrected if I am wrong in this instance. I am still new to this myself! :)
I need to parse the $PATH environment variable in my application.
So I was wondering what escape characters would be valid in $PATH.
I created a test directory called /bin:d and created a test script called funny inside it. It runs if I call it with an absolute path.
I just can't figure out how to escape : in $PATH I tried escaping the colon with \ and wrapping it into single ' and double " quotes. But always when I run which funny it can't find it.
I'm running CentOS 6.
This is impossible according to the POSIX standard. This is not a function of a specific shell, PATH handling is done within the execvp function in the C library. There is no provision for any kind of quoting.
This is the reason why including certain characters (anything not in the "portable filename character set" - colon is specifically called out as an example.) is strongly recommended against.
From SUSv7:
Since <colon> is a separator in this context, directory names that might be used in PATH should not include a <colon> character.
See also source of GLIBC execvp. We can see it uses the strchrnul and memcpy functions for processing the PATH components, with absolutely no provision for skipping over or unescaping any kind of escape character.
Looking at the function
extract_colon_unit
it seems to me that this is impossible. The : is unconditionally and
inescapably used as the path separator.
Well, this is valid at least for bash. Other shells may vary.
You could try mounting it
mount /bin:d /bind
PATH=/bind
According to http://tldp.org/LDP/abs/html/special-chars.html single quotes should preserve all special characters, so without trying it, I would think that '/bin:d' would work (with)in $PATH.
I am trying to add security of GET query to exec function.
If I remove escapeshellarg() function, it work fine. How to fix this issue?
ajax_command.php
<?php
$command = escapeshellarg($_GET['command']);
exec("/usr/bin/php-cli " . $command);
?>
Assume $_GET['command'] value is run.php -n 3
What security check I can also add?
You want escapeshellcmd (escape a whole command, or in your case, sequence of arguments) instead of escapeshellarg (escape just a single argument).
Notice that although you have taken special precautions, this code allows anyone to execute arbitrary commands on your server anyways, by specifying the whole php script in a -r option. Note that php.ini can not be used to restrict this, since the location of it can be overwritten with -c. In short (and with a very small error margin): This code creates a severe security vulnerability.
escapeshellarg returns a quoted value, so if it contains multiple arguments, it won't work, instead looking like a single stringesque argument. You should probably look at splitting the command up into several different parameters, then each can be escaped individually.
It will fail unless there's a file called run.php -n 3. You don't want to escape a single argument, you want to escape a filename and arguments.
This is not the proper way to do this. Have a single PHP script run all your commands for you, everything specified in command line arguments. Escape the arguments and worry about security inside that PHP file.
Or better yet, communicate through a pipe.