Deserializing of untrusted data using C# - static-code-analysis

I have the following C# code which is getting a "high" error from Checkmarx. I can't see anything wrong with it.
var dataDirectoryPath = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
var json = File.ReadAllText($"{dataDirectoryPath}{Path.DirectorySeparatorChar}somefile.json");
var settings = new
JsonSerializerSettings{TypeNameHandling=TypeNameHandling.None};
var targetPathSettings = JsonConvert.DeserializeObject<List<TargetPathSetting>>(json, settings);
It gives this error:
The serialized object ReadAllText processed in xxx in the file yyy is deserialized by DeserializeObject in the file zzz
The C# code is as follows:
public class TargetPathSetting
{
public string PathSettingName { get; set; }
public PathSetting PathSetting { get; set; }
}
public class PathSetting
{
public string BaseUrl { get; set; }
public string ApplicationIdUri { get; set; }
}
I can't see that anything that is ever in the file is going to cause any sort of problem, especially with the TypeNameHandling.None setting.

The problem is with the standard Checkmarx query for c #. In this case, Checkmarx does not recognize the correction of this code. To fix it you should use CxAudit and modify this query.

Related

.NET 5.0 Web API won't work with record featuring required properties

I'm using a C# 9.0 record type as a binding model for a .NET 5.0 Web API project. Some of the properties are required.
I'm using the record positional syntax, but am receiving errors.
public record Mail(
System.Guid? Id,
[property: Required]
string From,
[property: Required]
string[] Tos,
[property: Required]
string Subject,
string[]? Ccs,
string[]? Bccs,
[property: Required]
Content[] Contents,
Attachment[]? Attachments
);
This is then exposed as the binding model for my Index action:
public async Task<ActionResult> Index(Service.Models.Mail mailRequest)
{
…
}
Whenever I try to make a request, however, I receive the following error:
Record type 'Service.Models.Mail' has validation metadata defined on property 'Contents' that will be ignored. 'Contents' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
I tried removing the attribute on the Contents property, but it then fails for the next (prior) property. I tried using [param: …] instead of [property: …], as well as mixing them, but keep getting the same kind of error.
I looked around the web, and haven't found any suggestion of handling annotations differently for C# 9 records. I did my best, but I'm out of ideas—outside of converting my records to POCOs.
I gave up using Positional constructor, and with the verbose full declaration of the properties, it works.
public record Mail
{
public System.Guid? Id { get; init; }
[Required]
public string From { get; init; }
[Required]
public string[] Tos { get; init; }
[Required]
public string Subject { get; init; }
public string[]? Ccs { get; init; }
public string[]? Bccs { get; init; }
[Required]
public Content[] Contents { get; init; }
public Attachment[]? Attachments { get; init; }
public Status? Status { get; init; }
public Mail(Guid? id, string #from, string[] tos, string subject, string[]? ccs, string[]? bccs, Content[] contents, Attachment[]? attachments, Status status)
{
Id = id;
From = #from;
Tos = tos;
Subject = subject;
Ccs = ccs;
Bccs = bccs;
Contents = contents;
Attachments = attachments;
Status = status;
}
}
Try using only [Required] (instead of [property: Required]), for some reason worked for me
For me it started to work by adding the [ApiController] attribute to the controller.
I found something similar on ASP.NET Core Razor pages getting:
InvalidOperationException: Record type 'WebApplication1.Pages.LoginModelNRTB+InputModel' has validation metadata defined on property 'PasswordB' that will be ignored. 'PasswordB' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
from
Microsoft.AspNetCore.Mvc.ModelBinding.ModelMetadata.ThrowIfRecordTypeHasValidationOnProperties()
After some digging, I found: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ModelBinding/Validation/DefaultComplexObjectValidationStrategy.cs
So maybe as you've done, the verbose declaration is the way forward.
Positional record attributes in ASP.NET Core background
How do I target attributes for a record class? more background
Using FluentValidation and keeping properties with the full declaration seems to work perfectly in my case. I highly recommend trying this highly polished alternative validation library instead of using the pretty old standard data annotations
public record LoginViewModel
{
public string Mail { get; init; }
public string Password { get; init; }
public bool IsPersistent { get; init; }
}
public class LoginValidator : AbstractValidator<LoginViewModel>
{
public LoginValidator()
{
RuleFor(l => l.Mail).NotEmpty().EmailAddress();
RuleFor(l => l.Password).NotEmpty();
}
}

Asp.Net Web Api multiple files with additional data for each

I am trying to send multiple files along with some data for every file. This is my model:
public class FileDTO
{
[Required]
public IFormFile File { get; set; }
[Required]
public string CategoryName { get; set; }
[Required]
public string CategoryDescription { get; set; }
public string Detail { get; set; }
}
This is my controller:
[HttpPost("Upload/{id:int}")]
public async Task<IActionResult> Upload(int id, IEnumerable<FileDTO> appFileDTOs)
{
...
}
Is this even a correct way to do so? How do I send such a request in Postman to simulate it?
Thanks in advance!
Edit
I tried it like this in Postman:
Everything submits correctly besides the image. For some reason the image is always null...
[] represents collection/dictionary index while dot(.) represents there's a property.
So you should rename all the field names with the dot representation.
For example, change
appFileDTOs[0][File]
to
appFileDTOs[0].File
Demo
try this it may help you,
send from formData.
in model key send value as
[
{
"CategoryName":"Category1",
"CategoryDescription ":"Category1 Description",
"Detail":"Details "
},
{
"CategoryName":"Category2",
"CategoryDescription ":"Category2 Description",
"Detail":"Details2"
}
]
and for file send first file as file1 and second file as file2;
In server side , remove IEnumerable of FileDTO appFileDTOs from method name.
get value of model as
var data = JsonConvert.DeserializeObject<List<FileDTO>>(Request.Form["model"]);
simillary for file
var fileUpload1 = Request.Form.Files["file1"];
var fileUpload2 = Request.Form.Files["file2"];

Problems with Full Text Search in Postgresql & .Net Core 2.1

I post this question because I dont found similar issue yet. I'm trying to ensure Full Text Search in .net core app, and according to npgsql documentation I have:
1) Model
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public long License { get; set; }
public NpgsqlTsVector SearchVector { get; set; }
}
2) DatabaseContext:
modelBuilder.Entity<User>()
.HasIndex(p => p.SearchVector)
.ForNpgsqlHasMethod("GIN");
3) Migrations:
migrationBuilder.Sql(
#"CREATE TRIGGER user_search_vector_update BEFORE INSERT OR UPDATE
ON ""Users"" FOR EACH ROW EXECUTE PROCEDURE
ts`enter code here`vector_update_trigger(""SearchVector"", 'pg_catalog.english', ""Name"", ""Surname"");");
Now, I'm trying use FTS in my app, where method Search gets from header 'phase' (string).
[HttpGet]
public async Task<IActionResult> Search([FromHeader] string phase)
{
NpgsqlTsQuery tsVestor = EF.Functions.ToTsQuery("english", phase);
var response = Ok(_context.Users.Where(c => c.SearchVector.Matches(phase)).ToList());
return response;
}
I got:
NotSupportedException: Specified method is not supported.
Microsoft.EntityFrameworkCore.NpgsqlFullTextSearchDbFunctionsExtensions.ToTsQuery(DbFunctions _, string config, string query) in NpgsqlFullTextSearchDbFunctionsExtensions.cs
I also tried send by Header lexeme and comment line:
NpgsqlTsQuery tsVestor = EF.Functions.ToTsQuery("english", phase);
but i got: PostgresException: 42883: operator does not exist: tsvector ## text
Does anyone have any idea what I'm doing wrong?
EDIT ---- :
Ok, I found answer on my question. Converting from string to NpgsqlTsQuery must be inside Matches method:
public async Task<IActionResult> SearchUsers([FromHeader] string phase)
{
return Ok(_context.Users.Where(c => c.SearchVector.Matches(EF.Functions.ToTsQuery(phase))));
}
Placing this convertion outside Matches method threw "NotSupportedException", and putting plain text as function argument threw 42883 Exeception.
Now, it's clear what I was doing wrong.
As #sonofaforester suggests, I put answer on my own question:
Converting from string to NpgsqlTsQuery must be inside Matches method:
public async Task<IActionResult> SearchUsers([FromHeader] string phase)
{
return Ok(_context.Users.Where(c => c.SearchVector.Matches(EF.Functions.ToTsQuery(phase))));
}
Placing this conversation outside Matches method threw "NotSupportedException", and putting plain text as function argument threw 42883 Exception.

Xamarin Forms - Using SQLite and SQLite Extensions to implement foreign keys

I'm new to Xamarin forms and am up to the point where I now want to be persisting data entered by the user to an Sqlite db. Thankfully, there all plenty of examples to get you started, but thats as far as the help goes... I'm trying to implement a relationship between two entities 'Session' and 'HandHistory'.
A Session can have multiple HandHistories - immediately I saw that some sort of foreign key would be needed here to link these tables/entities together. I read in multiple articles and stack overflow questions that the standard 'sqlite-net-pcl' (by Frank A.Krueger) package offers nothing in terms of foreign keys, and that in order to acquire the functionality I needed to use the SQLiteNetExtensions library. I referred to this article for help:
https://bitbucket.org/twincoders/sqlite-net-extensions/overview
My entities look like this:
Session:
using SQLite;
using SQLiteNetExtensions.Attributes;
namespace PokerSession.Models
{
[Table("Session")]
[AddINotifyPropertyChangedInterface]
public class Session
{
public Session(bool newSession)
{
if (newSession)
{
CurrentlyActive = true;
//HandHistories = new ObservableCollection<HandHistory>();
}
}
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public SessionType SessionType { get; set; } = SessionType.Tournament;
public string Location { get; set; }
public DateTime Date { get; set; } = DateTime.Now;
public string GeneralNotes { get; set; }
public int MoneyIn { get; set; }
public int MoneyOut { get; set; }
public int ProfitLoss
{
get
{
var p = MoneyOut - MoneyIn;
if (p < 0)
return 0;
return p;
}
}
/// <summary>
/// If the session has not been completed, set this to true
/// </summary>
public bool CurrentlyActive { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public ObservableCollection<HandHistory> HandHistories { get; set; }
}
}
HandHistory:
using SQLite;
using SQLiteNetExtensions.Attributes;
namespace PokerSession.HandHistories
{
[Table("HandHistory")]
[AddINotifyPropertyChangedInterface]
public class HandHistory
{
public HandHistory()
{
}
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(Session))]
public int SessionId { get; set; }
[ManyToOne]
public Session Session { get; set; }
}
}
I also followed this article for the platform specific implementations for obtaining the SQLiteConnection for the local db:
https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/databases/
The error I'm getting:
'SQLiteConnection' does not contain a definition for 'UpdateWithChildren' and the best extension method overload 'WriteOperations.UpdateWithChildren(SQLiteConnection, object)' requires a receiver of type 'SQLiteConnection' PokerSession.Android, PokerSession.iOS C:\Poker Notes Live\PokerSession\PokerSession\PokerSession\Services\DataService.cs 46 Active
private SQLiteConnection _database;
public DataService()
{
_database = DependencyService.Get<ISqLite>().GetConnection();
_database.GetTableInfo("HandHistory");
_database.CreateTable<Session>();
_database.CreateTable<HandHistory>();
var session = new Session(false)
{
Location = "Test Location",
Date = new DateTime(2017, 08, 26),
MoneyIn = 35,
MoneyOut = 0,
SessionType = SessionType.Tournament,
GeneralNotes = "blah blah"
};
var hh = new HandHistory();
_database.Insert(session);
_database.Insert(hh);
session.HandHistories = new ObservableCollection<HandHistory> {hh};
_database.UpdateWithChildren(session);
}
So basically it's not allowing me to use the SQLite Extension methods with my SQLiteConnection object (_database) which is confusing as this is the whole point behind the Extension methods? Surely they're made to work with the SQLiteConnection object?? I've also noticed through my playing around that there seems to be two different types of SQLiteConnection... The one I'm currently using is in the 'SQLite' namespace, and another one in the SQLite.Net namespace. I have checked the one in the SQLite.Net namespace and it does seem to like the Extension methods but it requires me to change my platform specific implementation for obtaining the SQLiteConnection, but it would fail at runtime (complaining about my Session entity not having a PK??).
Quite a long winded question I know but it's better to provide more information than not enough, and I'm sure there must be others experiencing similar problems so please comment and offer any help possible, thank you.

Deserializing a PHP json encoded (json_encode) string with ASP.NET webservices

I am really struggling deserializing a PHP json encoded string in ASP.NET.
I am using nusoap and CakePHP 1.3 on the PHP side and mvc.net 4.0 on the web service side and everything was working well. However, I couldn’t figure out how to pass a complex array as one parameter of the webservice, so I had the idea of serializing it as json and passing a simple string. So far so good...
But I cannot for the life of me de-serialize the json_encoded string in ASP.NET [well, I’ve been trying for the last two hours at least ;)]
Here is what I have so far:
The PHP sends an array of products (product id as a GUID - sent as a string then converted on the web service side) and the number of products:
$args['products'] = json_encode($booking['Booking']['prs_products']);
This is received ok by the webservice as the following json string (products):
[{"BookingProducts":{"id":"2884f556-67ed-4eb8-98ca-a99dc27a2665","quantity":2}},{"BookingProducts":{"id":"f57854ba-0a9b-400b-bea0-bafdcb179b01","quantity":2}},{"BookingProducts":{"id":"7ff81128-c33c-4e6c-a33c-3ca40ccfb5d0","quantity":2}}]
I then try and populate a BookingProducts List<>. The BookingProducts class is as follows:
public class BookingProducts
{
public String id { get; set; }
public int quantity { get; set; }
public BookingProducts()
{
}
public BookingProducts(string id, int quantity)
{
this.id = id;
this.quantity = quantity;
}
}
I have tried both the [System.Web.Script.Serialization][2] and Newtonsoft.Json libraries as follows, but without success:
List<BookingProducts> productsList = new List<BookingProducts>();
try
{
productsList = JsonConvert.DeserializeObject<List<BookingProducts>>((products));
}
catch (Newtonsoft.Json.JsonSerializationException)
{
productsList = new JavaScriptSerializer().Deserialize<List<BookingProducts>>(products);
}
In both cases I get a list of empty products (or a serialization exception).
Hopefully someone has done this before, or can spot an obvious mistake!
What you really have here is a list of objects containing BookingProducts object. In order to deserialize it, you need to have something like this for your entity:
public class BookingProductsWrapper
{
public class BookingProductsInner
{
public string id { get; set; }
public int quantity { get; set; }
}
public BookingProductsInner BookingProducts { get; set; }
}
Now you can deserialize it using JavaScriptSerializer (for example):
System.Web.Script.Serialization.JavaScriptSerializer jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
List<BookingProductsWrapper> productsList = jsSerializer.Deserialize<List<BookingProductsWrapper>>(products);
That will do the trick.

Resources