The OWASP ESAPI Logging interface is a security-centric but thin abstraction on top of traditional high-performance logging API's. There are both Log4j and native Java Logging default ESAPI logging implementations. The Log4j implementation is especially mature.
The logging interface of the OWASP ESAPI library pre-defines 4 types of log files entries specific to the glory of security monitoring.
public static final EventType ....
SECURITY_SUCCESS = new EventType( "SECURITY SUCCESS", true);
SECURITY_FAILURE = new EventType( "SECURITY FAILURE", false);
EVENT_SUCCESS = new EventType( "EVENT SUCCESS", true);
EVENT_FAILURE = new EventType( "EVENT FAILURE", false);
Attributing every log entry with a security type is fundamental to ESAPI. Your implementation of ESAPI can extend or change this list if desired.
ESAPI also supports a hierarchy of logging levels which can be configured at runtime to determine the severity of events that are logged, so that those log entries below the current threshold that are discarded. This is a common logging API feature and includes the following severity levels (fatal, error, warning, info, debug, trace).
The ESAPI team considered simply adding a security severity level to Log4J, but decided that was not enough. We wanted to force a programmer to tag every log entry as a security event (or not), regardless of severity level. We did not add yet another logging abstraction to your life lightly.
The reference implementations also includes the following protections:
- encodes any CRLF characters included in log data in order to prevent log injection attacks
- optionally encodes HTML characters into the HTML entity to protect web based log viewing software
- provides a mechanism to log session ids referentially so that sessions can be tracked in log files without exposing real session identifiers that could be used to hijack active sessions
- provides a mechanism to automatically log HTTP post/get variables while allowing for masking of passwords and other security-critical information that should not be logged
Much of this is configurable in ESAPI.properties
ESAPI.Logger=org.owasp.esapi.reference.Log4JLogFactory
#ESAPI.Logger=org.owasp.esapi.reference.JavaLogFactory
Specify your application name if you wish to log it.
Logger.ApplicationName=ARMS
# If you use an HTML log viewer that does not properly HTML escape
# log data, you can set LogEncodingRequired to true
Logger.LogEncodingRequired=false
Logger.LogApplicationName=false
Logger.LogServerIP=false
# LogFileName, the name of the logging file. Provide a full directory path (e.g., C:\\ESAPI\\ESAPI_logging_file) if you
# want to place it in a specific directory.
Logger.LogFileName=ARMS_ESAPI_LOGFILE
# MaxLogFileSize, the max size (in bytes) of a single log file before it cuts over to a new one (default is 10,000,000)
Logger.MaxLogFileSize=10000000
#ESAPI.Logger=org.owasp.esapi.reference.JavaLogFactory
Specify your application name if you wish to log it.
Logger.ApplicationName=ARMS
# If you use an HTML log viewer that does not properly HTML escape
# log data, you can set LogEncodingRequired to true
Logger.LogEncodingRequired=false
Logger.LogApplicationName=false
Logger.LogServerIP=false
# LogFileName, the name of the logging file. Provide a full directory path (e.g., C:\\ESAPI\\ESAPI_logging_file) if you
# want to place it in a specific directory.
Logger.LogFileName=ARMS_ESAPI_LOGFILE
# MaxLogFileSize, the max size (in bytes) of a single log file before it cuts over to a new one (default is 10,000,000)
Logger.MaxLogFileSize=10000000
So now you want to (securely) log. Right on. Simply specify a logger in each class that requires logging:
private final Logger logger = ESAPI.getLogger(SimpleESAPIFilter.class.getName());
And log away!
logger.error(Logger.SECURITY_FAILURE, "session has expired, log out user");
Here is an example of a log entry from one of my projects at Aspect. I'm not deploying on a cluster, yet, so I supressed the server IP, port and appName via ESAPI.properties.
2009-06-29 05:48:25,281 WARN IntrusionDetector SECURITY FAILURE Anonymous:0@unknown:unknown Incorrect password provided for dave
org.owasp.esapi.errors.ValidationException: Login failed
at com.aspectsecurity.arms.web.SimpleESAPIFilter.doFilter(SimpleESAPIFilter.java:149)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:875)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Thread.java:595)
2009-06-29 05:48:25,281 ERROR com.aspectsecurity.arms.web.actions.ARMSBaseAction EVENT SUCCESS Anonymous:0@unknown:270186 ENTRY POINT FOR ALL ACTIONS: 1246268905281
2009-06-29 05:48:25,281 ERROR com.aspectsecurity.arms.service.HibernateAccessController SECURITY SUCCESS Anonymous:0@unknown:270186 START assertAuthorizedForAction : action=com.aspectsecurity.arms.web.actions.user.LoginSubmitAction
2009-06-29 05:48:25,281 ERROR com.aspectsecurity.arms.service.HibernateAccessController SECURITY SUCCESS Anonymous:0@unknown:270186 ACCESS GRANTED assertAuthorizedForAction completeActionName=com.aspectsecurity.arms.web.actions.user.LoginSubmitAction IS NOT MANAGED, SO ALLOW GLOBAL ACCESS
org.owasp.esapi.errors.ValidationException: Login failed
at com.aspectsecurity.arms.web.SimpleESAPIFilter.doFilter(SimpleESAPIFilter.java:149)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:875)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Thread.java:595)
2009-06-29 05:48:25,281 ERROR com.aspectsecurity.arms.web.actions.ARMSBaseAction EVENT SUCCESS Anonymous:0@unknown:270186 ENTRY POINT FOR ALL ACTIONS: 1246268905281
2009-06-29 05:48:25,281 ERROR com.aspectsecurity.arms.service.HibernateAccessController SECURITY SUCCESS Anonymous:0@unknown:270186 START assertAuthorizedForAction : action=com.aspectsecurity.arms.web.actions.user.LoginSubmitAction
2009-06-29 05:48:25,281 ERROR com.aspectsecurity.arms.service.HibernateAccessController SECURITY SUCCESS Anonymous:0@unknown:270186 ACCESS GRANTED assertAuthorizedForAction completeActionName=com.aspectsecurity.arms.web.actions.user.LoginSubmitAction IS NOT MANAGED, SO ALLOW GLOBAL ACCESS