
ASP.NET Core 5 Secure Coding Cookbook
By :

Web applications such as the ones developed with ASP.NET Core have a plethora of components and libraries that enable them to execute OS commands in the host. If not written securely, the code that composes and runs these commands can likely expose the ASP.NET Core web application to command injection exploitation. Shell commands can be executed unexpectedly if this security flaw in code is not prevented.
In this recipe, we will identify the command injection vulnerability in code and fix the security vulnerability.
Using Visual Studio Code, open the sample Online Banking app folder at Chapter02\command-injection\before\OnlineBankingApp
.
Here are the steps:
dotnet run
http://localhost:5000/Backups/Create
. Figure 2.5 – Backup page
backup & calc
, in the Backup Name field, and hit the Create button.Figure 2.6 – Successful command injection
If this security bug is not handled, this problem could also expose the underlying hosts to Remote Code Execution (RCE).
Let's take a look at the steps for this recipe:
code .
dotnet build
Services/BackupService.cs
file and locate the vulnerable part of the code in the BackupDB(string backupname)
method:public async Task BackupDB(string backupname) { using (Process p = new Process()) { string source = Environment.CurrentDirectory + "\\OnlineBank.db"; string destination = Environment.CurrentDirectory + "\\backups\\" + backupname; p.StartInfo.Arguments = " /c copy " + source + " " + destination; p.StartInfo.FileName = "cmd"; p.StartInfo.CreateNoWindow = true; ...code removed for brevity
public async Task FileCopyAsync(string sourceFileName, string destinationFileName, int bufferSize = 0x1000, CancellationToken cancellationToken = default(CancellationToken)) { using (var sourceFile = File.OpenRead(sourceFileName)) { using (var destinationFile = File.OpenWrite(destinationFileName)) { await sourceFile.CopyToAsync(destinationFile, bufferSize, cancellationToken); } } }
BackupDB
method and use the newly created method:public async Task BackupDB(string backupname) { string source = Environment.CurrentDirectory + "\\OnlineBank.db"; string destination = Environment.CurrentDirectory + "\\backups\\" + backupname; await FileCopyAsync(source, destination); }
We have refactored the BackUpDB
method to use the FileCopyAsync
method to limit your code to just perform file copying tasks, thereby preventing the execution of unwanted shell commands.
In our sample solution, administrators are allowed to provide a name to create a database backup. The BackUpDB
method accepts a user-controlled input parameter of the string
type. The input string is used to form a command that will initiate a command shell to have files copied from the source to the destination.
The added input string is expected to have the destination filename, but this can be manipulated to include commands that are more than just a value for an argument. Without validation or sanitization, this could cause the application to execute unwanted shell commands under the web application's identity and authorization.
One option of stopping OS command injection is to implement proper validation through the whitelisting technique. This technique can be achieved by using regular expressions (see the Input validation recipe in Chapter 1, Secure Coding Fundamentals):
System.Text.RegularExpressions
namespace:using System.Text.RegularExpressions;
RegEx
class and its IsMatch
method to validate the input against a pattern to only accept valid characters:public async Task BackupDB(string backupname) { var regex = new Regex(@"^[a-zA-Z0-9]+$"); if (!regex.IsMatch(backupname)) return; using (Process p = new Process()) { string source = Environment.CurrentDirectory + "\\OnlineBank.db"; string destination = Environment.CurrentDirectory + "\\backups\\" + backupname; p.StartInfo.Arguments = " /c copy " + source + " " + destination; p.StartInfo.FileName = "cmd"; p.StartInfo.CreateNoWindow = true; // code removed for brevity
We have now added a whitelisting validation with the use of the IsMatch
method. The IsMatch
method prevents non-alphanumeric characters and input from being processed in the succeeding lines of code, mitigating the risk of command injection.