Регистрация объектов со свойствами, которые содержат конфиденциальные данные (для хеширования) - PullRequest
3 голосов
/ 02 ноября 2019

Контекст

Я нахожусь в процессе разработки функциональности регистрации приложения.
Ищу элегантное и хорошее решение с точки зрения производительности.
(и, конечно, я не будуповторно внедрить колесо :). Я буду использовать популярную библиотеку журналов - например, Nlog, Serilog ...).

Требование

Журнал объекты , которые могут содержать свойства с конфиденциальной информацией .
Предположим, что класс человека:

class Person {
    string Name { get; set; }
    string SensitiveInfo { get; set; }
}

Плохой (на мой взгляд) подход - это делать что-то вроде этого:

logger.Debug($"{person.Name}, {Hash(person.SenstiveInfo)}");

Почему я нахожу это плохим?

  1. Это журнал отладки, который (в зависимости от уровня ведения журнала) может никогда не регистрироваться. Следовательно, он тратит ресурсы ЦП на хеширование без какой-либо необходимости.
  2. Я бы предпочел, чтобы объект передавался как есть (например, logger.Debug (person)), а не заставлял разработчика ломаться вручнуювсе свойства объекта.

Пока мысли ...

Для обоих приведенных ниже подходов требуется loggerWrapper, которого - если возможно - я хочу избежать:

class LoggerWrapper {
    LoggerWrapper (ILogger logger) {
        //store the ILogger
    }
    void Log(object objectToBeLogged, LoggingLevel level) {
        //If logging level is not accepted return
        _logger.Log(objectToBeLogged, level);
    }
}

1. Создание интерфейса ILoggable

interface ILoggable {
    string GetLogValue(HashManager hashManager);
}

class Person: ILoggable {
    string Name { get; set; }
    string SensitiveInfo { get; set; }

    string GetLogValue(HashManager hashManager) {
        string hashedValue = hashManager.Hash(person.SenstiveInfo);
        return $"{person.Name}, {hashedValue}"
    }
}

// Now the LogWrapper.Log will expect an ILoggable, and will use the 'GetLogValue' method
// overriding 'ToString()' is an alternative but it is exposed by the 'object' class, and i fear that is not strict enough/can be forgotten.

Относится к этому подходу: слишком требовательно для разработчиков? Ремонтопригодность?

2. Аннотации и рефлексия

class Person {
    [Loggable]
    string Name { get; set; }
    [Loggable, SensitiveInfo]
    string SensitiveInfo { get; set; }
}

// Now the logWrapper will rely on reflection (i think) and choose what to log/hash

Озабоченность этим подходом: производительность?


Считаются ли вышеуказанные подходы плохой практикой? Есть ли лучший подход?
Есть ли библиотеки, которые уже занимаются этим?

1 Ответ

1 голос
/ 02 ноября 2019

Ваш второй подход в порядке.

Я могу придумать несколько альтернативных подходов, но в конечном итоге они будут очень близки к тому, что есть у вас с аннотациями атрибутов.
- как хранение некоторой информации аннотаций во внешнем файле.
- или созданиеспециальный тип, например 'SensitiveInfo<T>', и используйте его там, где должно происходить хеширование, но это почти то же самое, что аннотировать свойства.

Для части исполнения:
Вы можете создатьодна временная структура в начале вашего приложения, которая сканирует все типы в сборках. Структура может быть словарём, имеющим имя типа в качестве ключа ("MyCompany.App.Core.Person"), и для значения вы можете иметь Func объект, созданный из динамически скомпилированного лямбда-выражения , которое будет возвращатьсообщение регистрации с хэшированными значениями, где это необходимо. (это будет сложная часть).
Важное примечание : Jit-компилятор не будет загружать DLL, пока не потребуется, поэтому попытайтесь создать эту структуру в самом начале загрузки, можете пропустить некоторые изсобрания. В качестве альтернативного подхода вы можете попытаться заполнить структуру по требованию (ленивый) как часть оболочки журнала.

Затем я пойду с оболочкой регистрации, которая будет использовать структуру для создания сообщения регистрации для конкретного объекта.

Несколько советов:
1. Регистрация тожемного информации не обязательно плохо, так что я бы не использовал атрибут [Loggable] - просто записывал все с объекта. Таким образом, накладные расходы для разработчика будут минимальными. Иногда в вашем объекте могут быть очень длинные строки, которые не важны, тогда вы можете ввести атрибут [NonLoggable].
2. Возможно, вы будете обрабатывать объекты иерархии - это добавит дополнительную сложность к созданию функции/ labbda expression.

В целом этот подход является более сложным, но менее требовательным для разработчиков.
В конце концов, это зависит от того, что вы и ваша команда готовы сделать, и объема работы, которая будетпотратить / сохранить (это будет зависеть от размера проекта и т. д.).


Я думаю, что первый подход будет трудно поддерживать и добавить много шума. Ведение журнала должно быть предметом инфраструктуры - максимально автоматизировано.

...