Reputation: 115
I wanted to mask the sensitive data like username/password using an slf4j framework. Immediate help is appreciated. Thanks in advance.
Upvotes: 4
Views: 23313
Reputation: 1051
Try this one.
First of all, we should create a class for handling our logs (each row)
public class PatternMaskingLayout extends PatternLayout {
private Pattern multilinePattern;
private List<String> maskPatterns = new ArrayList<>();
public void addMaskPattern(String maskPattern) { // invoked for every single entry in the xml
maskPatterns.add(maskPattern);
multilinePattern = Pattern.compile(
String.join("|", maskPatterns), // build pattern using logical OR
Pattern.MULTILINE);
}
@Override
public String doLayout(ILoggingEvent event) {
return maskMessage(super.doLayout(event)); // calling superclass method is required
}
private String maskMessage(String message) {
if (multilinePattern == null) {
return message;
}
StringBuilder sb = new StringBuilder(message);
Matcher matcher = multilinePattern.matcher(sb);
while (matcher.find()) {
if (matcher.group().contains("creditCard")) {
maskCreditCard(sb, matcher);
} else if (matcher.group().contains("email")) {
// your logic for this case
}
}
return sb.toString();
}
private void maskCreditCard(StringBuilder sb, Matcher matcher) {
//here is our main logic for masking sensitive data
String targetExpression = matcher.group();
String[] split = targetExpression.split("=");
String pan = split[1];
String maskedPan = Utils.getMaskedPan(pan);
int start = matcher.start() + split[0].length() + 1;
int end = matcher.end();
sb.replace(start, end, maskedPan);
}
}
The second step is we should create appender for logback into logback.xml
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.bpcbt.micro.utils.PatternMaskingLayout">
<maskPattern>creditCard=\d+</maskPattern> <!-- SourcePan pattern -->
<pattern>%d{dd/MM/yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%ex</pattern>-->
</layout>
</encoder>
</appender>
Now we can use logger into our code
log.info("card context set for creditCard={}", creditCard);
List item
As a result, we will see
one row from logs
card context set for creditCard=11111******111
without these options, our logs would be like this row
card context set for creditCard=1111111111111
Upvotes: 5
Reputation: 34011
Assuming you're using Java/Groovy. In your log4j2.xml, add something like:
<PatternLayout pattern="%mm"/>
then take that pattern and create a converter for it:
@Plugin(name = 'maskLog', category = 'Converter')
@ConverterKeys(['mm'])
class MaskLogConverter extends LogEventPatternConverter {
private static final String NAME = 'mm'
private MaskLogConverter(String[] options) {
super(NAME, NAME)
}
static LogMaskingConverter newInstance(final String[] options) {
return new LogMaskingConverter(options)
}
@Override
void format(LogEvent event, StringBuilder outputMessage) {
String message = event.message//.formattedMessage
// Do your masking logic here
outputMessage.append(message)
}
}
Inside that class you can mask, transform, parse, etc. accordingly.
Upvotes: 3
Reputation: 1153
Maybe this library will helpfull: owasp-security-logging
It related to OWASP Security Logging Project and provide related features:
LOGGER.info("userid={}", userid);
LOGGER.info(SecurityMarkers.CONFIDENTIAL, "password={}", password);
The intent is to produce the following output in the log:
2014-12-16 13:54:48,860 [main] INFO - userid=joebob
2014-12-16 13:54:48,860 [main] [CONFIDENTIAL] INFO - password=***********
More you can find in Wiki
Upvotes: 4
Reputation: 8227
The framework itself won't do the masking, nor should you expect it to. It's a very bad practice to pass confidential information to a reporting system. In your log.info()
call, make sure to substitute the password with asterisks. There is no point in masking the username because you might as well not log anything.
log.info("Successful login: {0} ********", username);
Upvotes: -9