How to automatically convert encrypted string column to decimal in C#? - c#

I'm working on an application in .Net Core 3.1 where we need to encrypt some database columns. Initially we tried to use SQL Server's own column-level encryption. But during the tests we came across some problems and conflicts with the certificate, because every time we changed the columns, the certificate stopped working.
Therefore, we decided to try another approach, applying encryption in the application itself. After some research, I found two packages:
EntityFrameworkCore.DataEncryption
EntityFrameworkCore.EncryptColumn
I followed some examples I found on the internet, and implemented an example using the EntityFrameworkCore.DataEncryption package. The problem is that encryption can only be applied to string-type fields and the data I need to encrypt is decimal, such as salary. As the application performs several operations involving these decimal fields, I would like to somehow perform the automatic conversion of the fields during reading and writing.
Example:
public class Produto
{
[Key]
public int IdProduto { get; set; }
public string NomeProduto { get; set; }
[Encrypted]
public string Valor { get; set; }
[Encrypted]
public string Desconto { get; set; }
[Encrypted]
public string ValorVenda { get; set; }
}
In my Product class, I need to encrypt some fields, they need to be string to work. I would like to somehow check if the field has the annotation [Encrypted] and when performing the get, it would be automatically converted to decimal and before persisting in the database, convert it again to string.
I've tried examples I've found, but so far without success. Could someone please tell me if this is possible and if so how could it be done?
Thank you

You can use reflection and check that the type/object has the [Encryption] attribute. I would adapt the code from this page:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/accessing-attributes-by-using-reflection
The key is to use reflection. You can read a class properties, methods etc to check for attributes.

Can you try something like adding an additional property for each of the fields you want encrypted, but don't map it to the database table. For example for ValorVenda:
// omit the [Encrypted] attribute
public string ValorVenda {get; set;}
[NotMapped]
public string ValorVendaLocal
{
get
{
// return decrypted ValorVenda
}
set
{
// ValorVenda = ... encrypt ValorVendaLocal
}
}

Related

Fixing the deserializing of untrusted data using C#

I have the following relevant C# code:
json = File.ReadAllText(path);
isStudentObject= JsonConvert.DeserializeObject<List<XXStudentCode>>(json).Any(sv => sv.SCODE.Equals(code));
My security software (static code analysis) scans our apps and it does not like the above code, namely ReadAllText part. It says that this is a "high risk deserialization of untrusted data."
So my question is this: how can I refactor this code to make the data "trusted?" I tried different validation methods and it did not work. Any help is appreciated.
Basically search for a way of turn off the warning (through annotation or configuration file). But, before you do this, consider the implications: you should make sure that the data that you read is treated as unsecure. In other words: if, in your "XXStudentCode" object, exists some kind of flag or attribute/property that unlock things like give permission to execute some critical code or access to private things you should make sure that you do not trust the object after serialization.
Ex:
class Person
{
public bool IsAdmin { get; set; }
public string Name { get; set ; }
}
In the example above if the input comes with the attribute 'IsAdmin' with value true and your system treat all "Person's" with this attribute as a admin so you will have a security flaw. To overcome this you should create classes that only contains attributes and properties that you really need to read.
Fixed Ex:
class PersonModel
{
public string Name { get; set ; }
public Person ToPerson()
{
new Person { Name = Name };
}
}
class Person
{
public bool IsAdmin { get; set; }
public string Name { get; set ; }
}
Now, using the PersonModel in the deserialization, the only properties that you really want will be loaded, the rest you be ignored by the serialization library. But, this will not make you free to security flaws. If the deserialization library have some kind of security issue you will be affected too.
Hope this help.

Return only a subset of properties of an object from an API

Say I have a database in which I am storing user details of this structure:
public class User
{
public string UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
}
I have a data access layer that works with this that contains methods such as GetById() and returns me a User object.
But then say I have an API which needs to return a users details, but not sensitive parts such as the PasswordHash. I can get the User from the database but then I need to strip out certain fields. What is the "correct" way to do this?
I've thought of a few ways to deal with this most of which involve splitting the User class into a BaseClass with non sensitive data and a derived class that contains the properties I would want kept secret, and then converting or mapping the object to the BaseClass before returning it, however this feels clunky and dirty.
It feels like this should be a relatively common scenario, so am I missing an easy way to handle it? I'm working with ASP.Net core and MongoDB specifically, but I guess this is more of a general question.
It seems for my purposes the neatest solution is something like this:
Split the User class into a base class and derived class, and add a constructor to copy the required fields:
public class User
{
public User() { }
public User(UserDetails user)
{
this.UserId = user.UserId;
this.Name = user.Name;
this.Email = user.Email;
}
public string UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
public class UserDetails : User
{
public string PasswordHash { get; set; }
}
The data access class would return a UserDetails object which could then be converted before returning:
UserDetails userDetails = _dataAccess.GetUser();
User userToReturn = new User(userDetails);
Could also be done using AutoMapper as Daniel suggested instead of the constructor method. Don't love doing this hence why I asked the question but this seems to be the neatest solution and requires the least duplication.
There are two ways to do this:
Use the same class and only populate the properties that you want to send. The problem with this is that value types will have the default value (int properties will be sent as 0, when that may not be accurate).
Use a different class for the data you want to send to the client. This is basically what Daniel is getting at in the comments - you have a different model that is "viewed" by the client.
The second option is most common. If you're using Linq, you can map the values with Select():
users.Select(u => new UserModel { Name = u.Name, Email = u.Email });
A base type will not work the way you hope. If you cast a derived type to it's parent type and serialize it, it still serializes the properties of the derived type.
Take this for example:
public class UserBase {
public string Name { get; set; }
public string Email { get; set; }
}
public class User : UserBase {
public string UserId { get; set; }
public string PasswordHash { get; set; }
}
var user = new User() {
UserId = "Secret",
PasswordHash = "Secret",
Name = "Me",
Email = "something"
};
var serialized = JsonConvert.SerializeObject((UserBase) user);
Notice that cast while serializing. Even so, the result is:
{
"UserId": "Secret",
"PasswordHash": "Secret",
"Name": "Me",
"Email": "something"
}
It still serialized the properties from the User type even though it was casted to UserBase.
If you want ignore the property just add ignore annotation in you model like this, it will skip the property when model is serializing.
[JsonIgnore]
public string PasswordHash { get; set; }
if you want ignore at runtime(that means dynamically).there is build function avilable in Newtonsoft.Json
public class User
{
public string UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
//FYI ShouldSerialize_PROPERTY_NAME_HERE()
public bool ShouldSerializePasswordHash()
{
// use the condtion when it will be serlized
return (PasswordHash != this);
}
}
It is called "conditional property serialization" and the documentation can be found here. hope this helps
The problem is that you're viewing this wrong. An API, even if it's working directly with a particular database entity, is not dealing with entities. There's a separation of concerns issue at play here. Your API is dealing with a representation of your user entity. The entity class itself is a function of your database. It has stuff on it that only matters to the database, and importantly, stuff on it that does not matter to your API. Trying to have one class that can satisfy multiple different applications is folly, and will only lead to brittle code with nested dependencies.
More to the point, how are you going to interact with this API? Namely, if your API exposes your User entity directly, then any code that consumes this API either must take a dependency on your data layer so it can access User or it must implement its own class representing a User and hope that it matches up with what the API actually wants.
Now imagine the alternative. You create a "common" class library that will be shared between your API and any client. In that library, you define something like UserResource. Your API binds to/from UserResource only, and maps that back and forth to User. Now, you have completely segregated your data layer. Clients only know about UserResource and the only thing that touches your data layer is your API. And, of course, now you can limit what information on User is exposed to clients of your API, simply by how you build UserResource. Better still, if your application needs should change, User can change without spiraling out as an API conflict for each consuming client. You simply fixup your API, and clients go on unawares. If you do need to make a breaking change, you can do something like create a UserResource2 class, along with a new version of your API. You cannot create a User2 without causing a whole new table to be created, which would then spiral out into conflicts in Identity.
Long and short, the right way to go with APIs is to always use a separate DTO class, or even multiple DTO classes. An API should never consume an entity class directly, or you're in for nothing but pain down the line.

Cmdlet: Have user enter complex data-types on powershell automatic prompting

I want to have my user enter data for my custom made data-type 'MyExampleType'.
pseudo-code:
[Cmdlet("Set", "MyExampleData")]
public class SetMyExampleData
{
[Parameter(Position = 0, Mandatory = true)]
public string Name{ get; set; }
[Parameter(Position = 1, Mandatory = true)]
public MyExampleType ExampleData { get; set; }
As far as I understand it, on automatic prompting, powershell expects the user to pass an instance of MyExampleType when asked for 'ExampleData'.
Is it somehow possible to make powershell ask for any value on its own? So, if 'MyExampleType' would look like this:
public class MyExampleType
{
public string Key { get; set; }
public string Value { get; set; }
That powershell then would ask for 'Key', and then for 'Value'?
I've generally trouble creating commandlets to provide basic configuration of a larger bit of software (in terms of adding sets of configuration data to it) and don't know a way yet to have the user enter data thats a bit more complex than just single values. Mabye I'm on the wrong way here generally...
You could write an intermediate function with all fields as parameters which will assign these parameters to your custom type object properties and then call this function without any parameter. In this case powershell will ask to enter every parameter's value. Example (assuming $obj is defined somewhere else):
function fillMyType
{
param(
[Parameter(Mandatory=$true)]$Key,
[Parameter(Mandatory=$true)]$Value
)
$obj.Key=$Key
$obj.Value=$Value
}
fillMyType

linq2db specify custom conversions for fields going to / from the database to convert to/from specific C# types

In the database we have to work with (which is DB2) there are fields stored as character but are in fact other objects, the most common being custom ways the underlying application stores dates and times. For example:
[Table]
public class ExampleTable {
// This is stored in the DB as a char in the format: 2016-01-11-11.39.53.492000
[Column(Name = "WTIMESTAMP")] public string WriteTimestamp { get; set; }
}
Would there be a way to tell linq2db a conversion method to use when converting to / from the database, that would also allow us to access those properties as an object we want (for instance, a C# DateTime object), but get saved back in the proper format?
One thing I thought of was something like:
[Table]
public class ExampleTable {
public DateTime WriteTimestamp { get; set; }
// This is stored in the DB as a char in the format: 2016-01-11-11.39.53.492000
[Column(Name = "WTIMESTAMP")] public string WriteTimestampRaw
{
get {
return ConvertWriteTimestampToDb2Format(WriteTimestamp);
}
set {
WriteTimestamp = ConvertWriteTimestampToDateTime(value);
}
}
}
And then we access WriteTimestamp, but the linq2db uses WriteTimestampRaw in the queries.
But, I'm not sure if that's the best or only option. Thanks in advance.
Well... just noticed that you said linq2db and not Entity Framework after I posted my answer. Maybe it will still give you some ideas, though.
What I have done before with Entity Framework (although not specifically with DB2, but I think it should still work), is to use the code provided in this answer to allow private properties to be mapped to a database column. Then, I have something similar to your code, except the getters and setters are reversed:
[Table("ExampleTable")]
public class ExampleTable
{
[NotMapped]
public DateTime WriteTimestamp
{
get
{
var db2Tstamp = DB2TimeStamp.Parse(WriteTimestampRaw);
return db2Tstamp.Value;
}
set
{
var db2Tstamp = new DB2TimeStamp(value);
WriteTimestampRaw = db2Tstamp.ToString();
}
}
// This is stored in the DB as a char in the format: 2016-01-11-11.39.53.492000
[Column("WTIMESTAMP")]
private string WriteTimestampRaw { get; set; }
}
I used the DB2TimeStamp class to handle the conversion between string and DateTime values, but you could probably do it however you're comfortable.
You can use MappingSchema.SetConverter method to set conversion between specific types on client side. Or MappingSchema.SetConverterExpression to create converters as a part of query tree.

Serialize embedded class / object independently or as string?

I am implementing a mongodb cache for this asp.net webapi output cache (I agree redis would be better / faster but for now, I need a mongodb implementation!)
Anyway,
I have a CachedItem class that holds my key / value:
[BsonIgnoreExtraElements]
public class CachedItem
{
[BsonElement("key")]
public string Key { get; set; }
[BsonElement("value")]
public object Value { get; set; }
}
Value is an object, that could be anything, we don't control that.
In one of my tests, I have a very simple poco:
public class UserFixture
{
public UserFixture()
{
Id = Guid.NewGuid();
}
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
When this is set to the Value it is serialized and persisted.
When I try to retrieve it, it fails to deserialize, as it has automatically grabbed the "Id" property.
An error occurred while deserializing the Id property of class WebAPI.OutputCache.MongoDb.Tests.UserFixture: Cannot deserialize Guid from BsonType ObjectId
Obviously, I can't decorate UserFixture
Is there any way I can tell MongoDB driver to basically serialize CachedItem.Value, as say, a string?
I could use JSON.net to do this before saving, and deserialize it on the way back out, but I was hoping to avoid this.
It's also on GitHub
That link should take you straight to the relevent commit if you'd like to try the failing test.
You can of course tell MongoDB to serialize your class as a string by building your own custom BsonSerializer. I have found it easier to inherit from their BsonStringSerializer. You also need to register that serializer with your specific type. (I suggest using a BsonSerializationProvider for that)
What you do need to think about is how to represent all your possible data as a string so you could deserialize it back to your application (Consider for example that you probably need to save the type information).

Categories

Resources