Base solution for your next web application
Open Closed

Securing sensitive information in audit and history logs #11345


User avatar
0
marble68 created

V11.3 MVC Core

I have entities with properties that could contain information that shouldn't be stored transparently in the logs.

In digging for securing history property values - It looks like I'd need to extend the EntityHistoryStore from here:

EntityHistoryHelper.cs

Specifically, during the changeset creation process.

For Audit logging - the JSON posted is stored (I'm not storying sent values) potentially contains sensitive information.

I'm thinking I should override the auditing helper from here:

AuditingHelper.cs

For properties, I'd examine the entity type and if it had a particular property (securelogs, regardless of value), it would mask the previous and new values in the history.

For audit logs, perhaps I'd put a regex in the secure logs and anything matching that regex would be masked in the raw JSON?

I'm not sure of the best approach to this. Because the data needs to be audited and history tracked due to the nature of the data, I need this information. However, because of the nature of the data, I don't want the actual values visible in the logs.

What would be the best approach would be to add an attribute to the property for masking the data, I suppose - but I first need to determine how, in my project, I can intercept the auditing and history to ensure data matching my pattern is masked in the JSON value auditing logs - and also masked in the property change history.

Any guidance is most appreciated.


5 Answer(s)
  • User Avatar
    0
    marble68 created

    After more digging - I apparently just need to replace the native EntityHistoryHelper with my own - but there's already a static object with the same name in the project in core project.

    I think it should be in the entityframeworkcore module - as that's where dbcontext lives.

    In the framework core, I have MyEntityHistoryHelper and everything looks good. In the entityframeworkcore module, I replace IEntityHistoryHelper with MyEntityHistoryHelper.

    Everything compiles and runs, but my entityhistoryhelper functions aren't called.

    Where do I do my configuration override?

  • User Avatar
    0
    marble68 created

    Based on responses to other people, do we override the EntityHistoryHelper or EntityHistoryHelperBase?

  • User Avatar
    0
    marble68 created
  • User Avatar
    0
    marble68 created

    I have this in the core project, which is a direct copy from abpzero project with no edits:

    using Abp.Domain.Uow;
    using Abp.EntityHistory;
    using Abp.EntityHistory.Extensions;
    using Abp.Events.Bus.Entities;
    using Abp.Extensions;
    using Abp.Json;
    using JetBrains.Annotations;
    using System;
    using System.Collections.Generic;
    using System.Data.Entity.Core;
    using System.Data.Entity.Core.Metadata.Edm;
    using System.Data.Entity.Core.Objects;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Reflection;
    using DbContext = System.Data.Entity.DbContext;
    using EntityState = System.Data.Entity.EntityState;
    using AbpEntityHistoryHelper = Abp.EntityHistory.EntityHistoryHelper;
    using System.Threading.Tasks;
    using System.Transactions;
    
    namespace mynamespace.EntityHistory
    {
        public class MyEntityHistoryHelper : AbpEntityHistoryHelper, IMyEntityHistoryHelper
        {
            public MyEntityHistoryHelper(IEntityHistoryConfiguration entityHistoryConfiguration, IUnitOfWorkManager unitOfWorkManager) : base(entityHistoryConfiguration, unitOfWorkManager)
            {
            }
    
            public EntityChangeSet CreateEntityChangeSet(DbContext context)
            {
                var changeSet = new EntityChangeSet
                {
                   .... code
    
                return changeSet;
            }
    
    
            public async Task SaveAsync(DbContext context, EntityChangeSet changeSet)
            {
               ... code
            }
    
            public void Save(DbContext context, EntityChangeSet changeSet)
            {
                ... code
            }
    
            [CanBeNull]
            protected virtual string GetEntityId(DbEntityEntry entityEntry, EntityType entityType)
            {
                 ... code
            }
    
            [CanBeNull]
            private EntityChange CreateEntityChange(DbEntityEntry entityEntry, EntityType entityType)
            {
                 ... code
            }
    
            private EntityType GetEntityType(ObjectContext context, Type entityType, bool useClrType = true)
            {
                 ... code
            }
    
            private EntitySet GetEntitySet(ObjectContext context, EntityType entityType)
            {
                 ... code
            }
    
            private static bool IsBaseTypeHasElementTypeName(string elementTypeName, EdmType entityEdmType)
            {
                ... code
            }
    
            /// <summary>
            /// Gets the property changes for this entry.
            /// </summary>
            private ICollection<EntityPropertyChange> GetPropertyChanges(DbEntityEntry entityEntry, EntityType entityType, EntitySet entitySet, bool auditedPropertiesOnly)
            {
                 ... code
            }
    
            /// <summary>
            /// Gets the property changes for this entry.
            /// </summary>
            private ICollection<EntityPropertyChange> GetRelationshipChanges(DbEntityEntry entityEntry, EntityType entityType, EntitySet entitySet, ICollection<ObjectStateEntry> relationshipChanges, bool auditedPropertiesOnly)
            {
                 ... code
            }
    
            /// <summary>
            /// Updates change time, entity id, Adds foreign keys, Removes/Updates property changes after SaveChanges is called.
            /// </summary>
            private void UpdateChangeSet(DbContext context, EntityChangeSet changeSet)
            {
                ... code
            }
    
            private EntityPropertyChange CreateEntityPropertyChange(object oldValue, object newValue, PropertyInfo propertyInfo)
            {
              ...
            }
    
    
        }
    }
    

    This is a copy of the EntityHistoryHelper in AspBoilderPlate.

    I put a break point on all public methods on the first line.

    Then, in every single PreInitialize method in the solution, I put the following as the very last command to try and ensure my custom entityhistoryhelper is used instead of the default.

    Configuration.ReplaceService<IEntityHistoryHelper, MyEntityHistoryHelper>(DependencyLifeStyle.Transient);
    

    I then edit an entity and Save, SaveAync, or CreateEntityChangeSet are not called.

    I've tried basing on EntityHistoryHelperBase as well.

    I'm obviously doing something wrong?

  • User Avatar
    0
    marble68 created

    Update - I was finally able to resolve this. The solution was to ensure to use the core classes from ABP, and ensure to substitue in framework core.