How masking of sensitive data is achieved using slf4j framework?

11,698

Solution 1

Try this one. 1. 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);
}

}

  1. 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>
    

  2. Now we can use logger into our code

    log.info("card context set for creditCard={}", creditCard);

  3. 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

Solution 2

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

Solution 3

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.

Share:
11,698
Raghvendra
Author by

Raghvendra

Updated on June 05, 2022

Comments

  • Raghvendra
    Raghvendra almost 2 years

    I wanted to mask the sensitive data like username/password using an slf4j framework. Immediate help is appreciated. Thanks in advance.

  • Kirill G.
    Kirill G. about 6 years
    You advise is bad because doing this manually is error prone. It is better to have a common generic solution for this to make sure nothing is missed.
  • Bob Dalgleish
    Bob Dalgleish about 6 years
    In my experience, you have to manually inspect every potential exposure of confidential data as part of your auditing process. Again, this is not the responsibility of the logging framework.
  • Ganesh Satpute
    Ganesh Satpute about 4 years
    No, log4j does support overwriting password by asterics.
  • Punisher660
    Punisher660 almost 4 years
    So I know this is a pretty old thread, but does anyone know where Utils.getMaskedPan(pan); comes from? What library has to be imported for that?
  • Alexandr Kovalenko
    Alexandr Kovalenko almost 4 years
    Utils.getMaskedPan(pan) - this is my own method ) with the custom realization of mask sensitive data.
  • dasun_001
    dasun_001 about 3 years
    Hi, Cant we take private static final String NAME = 'mm' from application.properties file?
  • S.Javed
    S.Javed almost 3 years
    Checking every log call for sensitive data leak in a big application is impractical and you can never guarantee human errors.