Bruce Brouwer created LOG4J2-439:
------------------------------------

             Summary: Create a LogEventPatternConverter to escape newlines and 
HTML special characters
                 Key: LOG4J2-439
                 URL: https://issues.apache.org/jira/browse/LOG4J2-439
             Project: Log4j 2
          Issue Type: New Feature
          Components: Layouts
    Affects Versions: 2.0-beta9
            Reporter: Bruce Brouwer


To prevent log forging and HTML based attacks from viewing logs in a browser, 
we could add a LogEventPatternConverter that escapes newlines and HTML special 
characters. [ESAPI has a method to do 
this|http://owasp-esapi-java.googlecode.com/svn/trunk_doc/2.0-rc7/apidocs/org/owasp/esapi/Logger.html],
 but it doesn't have any of the nice API features that Log4j 2 has. 

I was able to create a LogEventPatternConverter to do this. Note, this is only 
a proof of concept. I didn't try to exhaustively list all the special 
characters that might need to be replaced. I also didn't provide any 
configuration so we could choose to not escape HTML, for example.

With this configuration:
{code:xml}
<PatternLayout pattern="%d %-5p [%t] %c %encode{%m}%n"/>
{code}

And logging this message:
{code}
LOG.warn("hi\n & <h1> there");
{code}

Would result in this being logged:
{code}
2013-10-28 16:31:21,606 WARN  [main] example.Test hi\n &amp; &lt;h1&gt; there 
{code}

instead of this (which shows the potential for log forging):
{code}
2013-10-28 16:31:21,606 WARN  [main] example.Test hi
& <h1> there 
{code}

This is roughly the code I used:
{code}
@Plugin(name = "escape", category = "Converter")
@ConverterKeys({ "escape" })
public final class EscapingReplacementConverter extends 
LogEventPatternConverter {

    private final List<PatternFormatter> formatters;

    private EscapingReplacementConverter(final List<PatternFormatter> 
formatters) {
        super("escape", "escape");
        this.formatters = formatters;
    }

    public static EscapingReplacementConverter newInstance(final Configuration 
config,
                                                           final String[] 
options) {
        if (options.length != 1) {
            LOGGER.error("Incorrect number of options on escape. Expected 1, 
received "
                    + options.length);
            return null;
        }
        if (options[0] == null) {
            LOGGER.error("No pattern supplied on escape");
            return null;
        }
        final PatternParser parser = PatternLayout.createPatternParser(config);
        final List<PatternFormatter> formatters = parser.parse(options[0]);
        return new EscapingReplacementConverter(formatters);
    }

    @Override
    public void format(final LogEvent event, final StringBuilder toAppendTo) {
        final StringBuilder buf = new StringBuilder();
        for (final PatternFormatter formatter : formatters) {
            formatter.format(event, buf);
        }
        toAppendTo.append(buf.toString()
                             .replaceAll("\\r", "\\\\r")
                             .replaceAll("\\n", "\\\\n")
                             .replaceAll("&", "&amp;")
                             .replaceAll("<", "&lt;")
                             .replaceAll(">", "&gt;"));
    }
}
{code}

If this sounds good, I would like to hear feedback and ideas on how to make 
this better. I will then contribute this to the project. Do you think this 
could this get in 2.0?



--
This message was sent by Atlassian JIRA
(v6.1#6144)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to