Skip to content

Commit

Permalink
Merge pull request #88 from pappyangel/SQLInjection
Browse files Browse the repository at this point in the history
Fix Sql injection issues and add env display
  • Loading branch information
timrobertsusa authored Aug 9, 2024
2 parents c27416b + 7c3c22c commit 2ab56c9
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"request": "launch",
"preLaunchTask": "build API",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/cocktails/bin/Debug/net7.0/cocktails.dll",
"program": "${workspaceFolder}/cocktails/bin/Debug/net8.0/cocktails.dll",
"args": [],
"cwd": "${workspaceFolder}/cocktails",
"stopAtEntry": false,
Expand Down
10 changes: 7 additions & 3 deletions cocktails/Controllers/CocktailController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,13 @@ public async Task<ActionResult<string>> UpdateCocktail(Item item)
}

// cocktail/Post -- Delete Item
[HttpDelete("id/{id:int}")]

//[HttpDelete]
public async Task<ActionResult<string>> DeleteCocktail(int id)
//public async Task<ActionResult<string>> DeleteCocktail(Item item)

[HttpDelete("id/{id:int}")]
public async Task<ActionResult<string>> DeleteCocktail(int id)

{
int rowsAffected;

Expand All @@ -182,7 +186,7 @@ public async Task<ActionResult<string>> DeleteCocktail(int id)
return NotFound();


_logger.LogInformation("Received request to delete by this item id: {@int}", id);
_logger.LogInformation("Received request to delete this item: {@int}", id);

return $"Row(s) deleted were: {rowsAffected}";

Expand Down
77 changes: 65 additions & 12 deletions cocktails/DB/SqlDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Threading.Tasks;
using cocktails.models;
using Microsoft.Extensions.Configuration;
using System;

namespace cocktails.DB
{
Expand All @@ -30,12 +31,19 @@ public SqlDb(IConfiguration configuration)

public SqlConnection GetSQLCn()
{
var env = _configuration["ASPNETCORE_ENVIRONMENT"];
bool isDevelopment = env == "Development";

var builder = new SqlConnectionStringBuilder(
_configuration["ConnectionStrings:defaultConnection"]);

if (isDevelopment)
{
// The below 2 lines are used during development only. SMI is used in Production
var keyVaultSecretLookup = _configuration["AzureKeyVaultSecret:defaultSecret"];
builder.Password = _configuration.GetValue<string>(keyVaultSecretLookup);
}

// The below 2 lines are used during development only. SMI is used in Production
var keyVaultSecretLookup = _configuration["AzureKeyVaultSecret:defaultSecret"];
// builder.Password = _configuration.GetValue<string>(keyVaultSecretLookup);

SqlConnection sqlDBCn = new SqlConnection(builder.ConnectionString);

Expand Down Expand Up @@ -161,7 +169,50 @@ private int CRUD(string sqlStatetment)
return rowsAffected;

}
private async Task<int> CRUDAsync(string sqlStatetment)
private async Task<int> CRUDAsync(string sqlStatetment, Item item)
{
int rowsAffected = 0;

using SqlConnection SQLCn = GetSQLCn();

using SqlCommand crudCommand = new SqlCommand(sqlStatetment, SQLCn);
crudCommand.CommandType = CommandType.Text;

bool IgnoreCase = true;
if (sqlStatetment.StartsWith("D", IgnoreCase, null) | sqlStatetment.StartsWith("U", IgnoreCase, null))
crudCommand.Parameters.Add("@ItemId", SqlDbType.Int).Value = item.Id;

if (sqlStatetment.StartsWith("I", IgnoreCase, null) | sqlStatetment.StartsWith("U", IgnoreCase, null))
{
crudCommand.Parameters.Add("@ItemName", SqlDbType.VarChar, 50).Value = item.Name;
var paramPrice = crudCommand.Parameters.Add("@ItemPrice", SqlDbType.Decimal);
paramPrice.Value = item.Price;
paramPrice.Precision = 10;
paramPrice.Scale = 2;
var paramRating = crudCommand.Parameters.Add("@ItemRating", SqlDbType.Decimal);
paramRating.Value = item.Rating;
paramRating.Precision = 10;
paramRating.Scale = 2;
crudCommand.Parameters.Add("@ItemImagePath", SqlDbType.VarChar, 255).Value = item.ImagePath;
}

try
{
await SQLCn.OpenAsync();
rowsAffected = await crudCommand.ExecuteNonQueryAsync();
}
catch (Exception Ex)
{
string methodReturnValue = Ex.Message;
rowsAffected = -1;
// throw;
}

return rowsAffected;

}

private async Task<int> oldCRUDAsync(string sqlStatetment)
{
SqlCommand command;
int rowsAffected;
Expand All @@ -182,29 +233,31 @@ private async Task<int> CRUDAsync(string sqlStatetment)
public async Task<int> DeleteItembyId(int id)
{
int crudResult;
string sql = $"Delete from {tblName} where Id = {id}";
Item itemToDelete = new Item { Id = id };

crudResult = await CRUDAsync(sql);
string sql = $"Delete from {tblName} where Id = @ItemId";

crudResult = await CRUDAsync(sql, itemToDelete);

return crudResult;
}

public async Task<int> UpdateItembyId(Item item)
{
int crudResult;
string sql = $"Update t Set t.name = '{item.Name}', t.price = {item.Price}, t.rating = {item.Rating}, t.ImagePath = '{item.ImagePath}'"
+ $" From {tblName} t where t.id = {item.Id}";
string sql = $"Update t Set t.name = @ItemName, t.price = @ItemPrice, t.rating = @ItemRating, t.ImagePath = @ItemImagePath"
+ $" From {tblName} t where t.id = @ItemId";

crudResult = await CRUDAsync(sql);
crudResult = await CRUDAsync(sql,item);

return crudResult;
}
public async Task<int> InsertItem(Item item)
{
int crudResult;
string sql = $"Insert into {tblName} (Name, Price ,Rating) values ('{item.Name}', {item.Price}, {item.Rating})";

crudResult = await CRUDAsync(sql);
string sql = $"Insert into {tblName} (Name, Price ,Rating, ImagePath) values (@ItemName, @ItemPrice, @ItemRating, @ItemImagePath)";
item.ImagePath = item.ImagePath ?? "NoImageSelected.png";
crudResult = await CRUDAsync(sql, item);

return crudResult;
}
Expand Down
4 changes: 2 additions & 2 deletions cocktails/Data/Create and Populate Item for Cocktail.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ GO
-- Create the table in the specified schema
CREATE TABLE [dbo].[Items] (
[Id] INT IDENTITY (1001, 1) NOT NULL,
[Name] VARCHAR (20) NULL,
[Name] VARCHAR (50) NULL,
[Price] NUMERIC (10, 2) NULL,
[Rating] NUMERIC (10, 2) NULL,
[ImagePath] VARCHAR (255) CONSTRAINT [DEFAULT_Items_ImagePath] DEFAULT ('NoImage.jpg') NULL,
[ImagePath] VARCHAR (255) CONSTRAINT [DEFAULT_Items_ImagePath] DEFAULT ('NoImageSelected.png') NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
Expand Down
2 changes: 1 addition & 1 deletion cocktails/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
"cocktails": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
Expand Down
12 changes: 11 additions & 1 deletion cocktails/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"AzureServicesAuthConnectionString": "RunAs=Developer;DeveloperTool=AzureCli;",
"ManagedIdentity-AzureServicesAuthConnectionString": "RunAs=App",
"LocalDev-AzureServicesAuthConnectionString": "RunAs=Developer;DeveloperTool=AzureCli;",
"ConnectionStrings": {
"defaultConnection": "Server=tcp:jfv-sql.database.windows.net,1433;Initial Catalog=dbItems;Persist Security Info=False;User ID=dbadmin;Password=;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30",
"ProductionConnection-ManagedIdentity": "Server=tcp:jfv-sql.database.windows.net;Authentication=Active Directory Default; Database=dbItems;",
"DevelopmentConnection-SQLAuth": "Server=tcp:jfv-sql.database.windows.net,1433;Initial Catalog=dbItems;Persist Security Info=False;User ID=dbadmin;Password=;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30",
"MCAPSOld-defaultConnection": "Server=tcp:sql-jfv.database.windows.net;Authentication=Active Directory Default; Database=SocialEvents;",
"MCAPSOld-defaultSQLAuthConnection": "Server=tcp:sql-jfv.database.windows.net,1433;Initial Catalog=SocialEvents;Persist Security Info=False;User ID=dbadmin;Password=;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30"
}



Expand Down
9 changes: 7 additions & 2 deletions frontend/Models/APICocktailRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,17 @@ public async Task<List<Item>> AddItemAsync(Item cocktailToAdd)
return cocktailList;
}

public async Task<List<Item>> DeleteItemAsync(int cocktailIdToDelete)
//public async Task<List<Item>> DeleteItemAsync(int cocktailIdToDelete)
public async Task<List<Item>> DeleteItemAsync(Item cocktailToDelete)
{

var deleteUrl = apiUrl + "/id/" + cocktailIdToDelete;
var deleteUrl = apiUrl + "/id/" + cocktailToDelete.Id;
var response = await APIclient.DeleteAsync(deleteUrl);

// var jsonItem = JsonSerializer.Serialize(cocktailIdToDelete);
// var httpContent = new StringContent(jsonItem, Encoding.UTF8, "application/json");
// var response = await APIclient.DeleteAsync(apiUrl, httpContent)


cocktailList = await APIclient.GetFromJsonAsync<List<Item>>(apiUrl);

Expand Down
2 changes: 1 addition & 1 deletion frontend/Models/ICocktailRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface ICocktailRepository
Task<List<Item>> UpdateItemAsync(Item updatedItem);

Task<List<Item>> AddItemAsync(Item cocktailToAdd);
Task<List<Item>> DeleteItemAsync(int cocktailIdToDelete);
Task<List<Item>> DeleteItemAsync(Item cocktailToDelete);

}

Expand Down
5 changes: 3 additions & 2 deletions frontend/Pages/DeleteCocktail.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ public IActionResult OnGet(int id)
public async Task<IActionResult> OnPost(Item cocktailToDelete)
{
// call the add method
await cocktailRepository.DeleteItemAsync(cocktailToDelete.Id);

//await cocktailRepository.DeleteItemAsync(cocktailToDelete.Id);
await cocktailRepository.DeleteItemAsync(cocktailToDelete);

// redirect to summary page
return Redirect("/Cocktails");

Expand Down
7 changes: 7 additions & 0 deletions frontend/Pages/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@
<p>July 2024</p>
<p><a href="https://cocktail-api.azurewebsites.net/cocktails">Hit the API directly!</a></p>
</div>

<environment include="Development">
<div>Environment is Development</div>
</environment>
<environment exclude="Development">
<div>Environment is NOT Development</div>
</environment>
4 changes: 2 additions & 2 deletions frontend/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
},
"frontend": {
"commandName": "Project",
"dotnetRunMessages": "true",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"applicationUrl": "https://localhost:3001;http://localhost:3000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
Expand Down
12 changes: 8 additions & 4 deletions frontend/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
},
"AllowedHosts": "*",
"APIProductionUrl": "http://127.0.0.1:5000/cocktails",
"FY25-APIProductionUrl": "https://cocktail-api.azurewebsites.net/cocktails",
"Dev-APIUrl": "http://127.0.0.1:5000/cocktails"
}

0 comments on commit 2ab56c9

Please sign in to comment.