2015-05-08 8 views
7

Ich benutze log4net als mein Protokollierungsrahmen der Wahl für ein neues Projekt, das in Kürze startet. Ein Problem, auf das ich beim Prototyping gestoßen bin und für das ich keine definitive Antwort finden kann, ist, wie Sie Nachrichteninhalte auf eine konfigurierbare und saubere Weise bereinigen oder maskieren können.Konfigurierbare sensitive Datenmaskierung über log4net

Hypothetisch sagen wir, ich möchte, dass mehrere Reiniger in Aktion treten, aber ich möchte auch dem Grundsatz der einheitlichen Verantwortung folgen. Einige Reiniger Beispiele:

  • Kartennummer/PAN-Reiniger
  • Passwort Reiniger
  • privaten Daten Reiniger

Ich weiß, dass Sie sollten nie diese Art von Informationen im Klartext werden Protokollierung und die Ausführung von Code Die Logbücher werden das niemals wissentlich tun. Ich möchte jedoch eine letzte Stufe des Schutzes haben, falls Daten missbräuchlich werden und sensible Daten irgendwie irgendwo hineinkommen, wo es nicht sollte; Protokolle sind das Worst-Case-Szenario.

Option 1:

ich diesen Artikel Stackoverflow gefunden habe, die jedoch eine mögliche Lösung Details geht es um die Verwendung der Reflexion. Dies ist nicht wünschenswert für die Leistung, aber es scheint auch Hacky zu manipulieren interne Speichermechanismen. Editing-log4net-messages-before-they-reach-the-appenders

Option 2:

Die vorgeschlagene Antwort auf die gleiche Frage schlägt die Verwendung eines PatternLayoutConverter. Dies ist für einen einzelnen Reiniger Betrieb in Ordnung, aber Sie sind nicht in der Lage mehrere Operationen verwendet werden, wie die folgenden:

public class CardNumberCleanerLayoutConverter : PatternLayoutConverter 
{ 
    protected override void Convert(TextWriter writer, LoggingEvent loggingEvent) 
    { 
     string message = loggingEvent.RenderedMessage; 

     // TODO: Replace with real card number detection and masking. 
     writer.Write(message.Replace("9", "*")); 
    } 
} 
<layout type="log4net.Layout.PatternLayout"> 
    <converter> 
     <name value="cleanedMessage" /> 
     <type value="Log4NetPrototype.CardNumberCleanerLayoutConverter, Log4NetPrototype" /> 
    </converter> 
    <converter> 
     <name value="cleanedMessage" /> 
     <type value="Log4NetPrototype.PasswordCleanerLayoutConverter, Log4NetPrototype" /> 
    </converter> 
    <conversionPattern value="%cleanedMessage" /> 
</layout> 

Im Fall einer Namenskollision, wie oben gezeigt, wird der Konverter geladen zuletzt derjenige was ausgeführt wird. Im obigen Beispiel bedeutet dies, dass Passwörter gesäubert werden, jedoch keine Kartennummern.

Option 3:

Eine dritte Option, die ich versucht habe, ist die Verwendung von verketteten ForwarderAppender Fällen aber dies erschwert schnell die Konfiguration und ich würde es eine ideale Lösung nicht in Betracht ziehen. Da die Logging Klasse eine unveränderliche RenderedMessage Eigenschaft hat, sind wir nicht in der Lage, es zu ändern, ohne eine neue Instanz der Logging Klasse zu schaffen und man es durch, wie unten gezeigt:

public class CardNumberCleanerForwarder : ForwardingAppender 
{ 
    protected override void Append(LoggingEvent loggingEvent) 
    { 
     // TODO: Replace this with real card number detection and masking. 
     string newMessage = loggingEvent.RenderedMessage.Replace("9", "*"); 

     // What context data are we losing by doing this? 
     LoggingEventData eventData = new LoggingEventData() 
     { 
     Domain = loggingEvent.Domain, 
     Identity = loggingEvent.Identity, 
     Level = loggingEvent.Level, 
     LocationInfo = loggingEvent.LocationInformation, 
     LoggerName = loggingEvent.LoggerName, 
     ExceptionString = loggingEvent.GetExceptionString(), 
     TimeStamp = loggingEvent.TimeStamp, 
     Message = newMessage, 
     Properties = loggingEvent.Properties, 
     ThreadName = loggingEvent.ThreadName, 
     UserName = loggingEvent.UserName 
     }; 

     base.Append(new LoggingEvent(eventData)); 
    } 
} 

public class PasswordCleanerForwarder : ForwardingAppender 
{ 
    protected override void Append(LoggingEvent loggingEvent) 
    { 
     // TODO: Replace this with real password detection and masking. 
     string newMessage = loggingEvent.RenderedMessage.Replace("4", "*"); 

     // What context data are we losing by doing this? 
     LoggingEventData eventData = new LoggingEventData() 
     { 
     Domain = loggingEvent.Domain, 
     Identity = loggingEvent.Identity, 
     Level = loggingEvent.Level, 
     LocationInfo = loggingEvent.LocationInformation, 
     LoggerName = loggingEvent.LoggerName, 
     ExceptionString = loggingEvent.GetExceptionString(), 
     TimeStamp = loggingEvent.TimeStamp, 
     Message = newMessage, 
     Properties = loggingEvent.Properties, 
     ThreadName = loggingEvent.ThreadName, 
     UserName = loggingEvent.UserName 
     }; 

     base.Append(new LoggingEvent(eventData)); 
    } 
} 

Matching-Konfiguration (sehr schwer zu folgen):

Hat jemand einen anderen Vorschlag, wie dies implementiert werden könnte, wo theoretisch n Anzahl von Reinigern auf Kosten der Leistung konfiguriert werden könnte?

Antwort

-1

In Ihrer Frage sagen Sie bereits, dass Sie zur Ursache gehen und keine sensiblen Daten protokollieren sollten. Dies kann durch eine vierte Option der Verwendung von Codeüberprüfungen erzwungen werden und die zu protokollierenden Daten betrachten. Ihre Protokollierungsanweisungen sollten niemals sensible Daten protokollieren, da dies ein Sicherheitsrisiko darstellt.Wenn Sie auf einen Code mit Filtern vertrauen, werden die sensiblen Daten wahrscheinlich nicht mehr funktionieren, wenn Sie Änderungen an Ihrem Projekt vornehmen. Ihr QA-Prozess muss wirklich gut sein, um diese Art von Fehlern zu erfassen (ich habe noch nie einen Tester gesehen, der alle Protokolle durchging). Also würde ich für Option 4 gehen, die sicherstellt, dass Sie diese Art von Informationen überhaupt nicht protokollieren.

+0

Ich stimme Ihnen vollkommen zu, dass alle Vorkehrungen getroffen werden sollten, um sicherzustellen, dass diese Art von Daten überhaupt nicht protokolliert wird. Wir beschäftigen uns mit großen Datenmengen von unseren Kunden, die wir dann mit ziemlich komplexen Regel-Engines abarbeiten. Wenn ein Debug-Protokoll beispielsweise angibt, dass die Kontonummer xyz aufgrund der Regel abc fehlgeschlagen ist, aber aus irgendeinem Grund vertrauliche Daten im Kontonummernfeld gesendet wurden, möchten wir dies erkennen können. Eine Erkennungslogik an jedem Punkt, an dem ein Diagnoseprotokoll erstellt werden könnte, würde zu einer massiven Codeverdopplung führen. Ich würde einen einzelnen Punkt bevorzugen, daher meine Frage. –

+0

Auch toll Punkt über die Code-Bewertungen. Wir haben eine strenge Richtlinie zur Codeüberprüfung, bei der jeder Code, der in der Produktion endet, von mindestens zwei anderen Entwicklern überprüft werden muss. Leider können selbst mit drei Augenblicken auf einen Codeblock Dinge übersehen werden und ich möchte sicherstellen, dass wir alle Abwehrmechanismen haben, die wir aufbringen können. –