开发者

C++: How to escape user input for safe system calls?

On a Linux platform, I have C++ code that goes like this:

// ...
std::string myDir;
myDir = argv[1]; // myDir is initialized using user input from the command line.
std::string command;
command = "mkdir " + myDir;
if (system(command.c_str开发者_运维技巧()) != 0) {
   return 1;
}
// continue....
  • Is passing user input to a system() call safe at all?
  • Should the user input be escaped / sanitized?
  • How?
  • How could the above code be exploited for malicious purposes?

Thanks.


Just don't use system. Prefer execl.

execl ("/bin/mkdir", "mkdir", myDir, (char *)0);

That way, myDir is always passed as a single argument to mkdir, and the shell isn't involved. Note that you need to fork if you use this method.

But if this is not just an example, you should use the mkdir C function:

mkdir(myDir, someMode);


Using system() call with command line parameters without sanitizing the input can be highly insecure.

The potential security threat could be a user passing the following as directory name

somedir ; rm -rf /

To prevent this , use a mixture of the following

  • use getopt to ensure your input is sanitized
  • sanitize the input
  • use execl instead of system to execute the command

The best option would be to use all three


Further to Matthew's answer, don't spawn a shell process unless you absolutely need it. If you use a fork/execl combination, individual parameters will never be parsed so don't need to be escaped. Beware of null characters however which will still prematurely terminate the parameter (this is not a security problem in some cases).

I assume mkdir is just an example, as mkdir can trivially be called from C++ much more easily than these subprocess suggestions.


Reviving this ancient question as I ran into the same problem and the top answers, based on fork() + execl(), weren't working for me. (They create a separate process, whereas I wanted to use async to launch the command in a thread and have the system call stay in-process to share state more easily.) So I'll give an alternative solution.

It's not usually safe to pass user input as-is, especially if the utility is designed to be sudo'd; in order to sanitize it, instead of composing the string to be executed yourself, use environment variables, which the shell has built-in escape mechanisms for.

For your example:

// ...
std::string myDir;
myDir = argv[1]; // myDir is initialized using user input from the command line.
setenv("MY_DIR", myDir, 1);
if (system("mkdir \"${MY_DIR}\"") != 0) {
   return 1;
}
// continue....
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜