Vit*_*sok 9 java logging spring esapi veracode
有一个Spring全局@ExceptionHandler(Exception.class)
方法可以记录异常:
@ExceptionHandler(Exception.class)
void handleException(Exception ex) {
logger.error("Simple error message", ex);
...
Run Code Online (Sandbox Code Playgroud)
Veracode扫描表明此日志记录已经Improper Output Neutralization for Logs
建议使用ESAPI记录器.有没有办法在不将记录器更改为ESAPI的情况下修复此漏洞?这是我遇到此问题的代码中唯一的地方,我试图找出如何以最小的更改来修复它.也许ESAPI有一些我没有注意到的方法?
PS当前记录器是slf4j上的Log4j
UPD: 最后我使用了ESAPI记录器.我以为它不会使用我的默认日志服务,但我错了,它只是使用我的slf4j logger接口和适当的配置.
private static final Logger logger = ESAPI.getLogger(MyClass.class);
...
logger.error(null, "Simple error message", ex);
Run Code Online (Sandbox Code Playgroud)
ESAPI具有log4j记录器和记录器工厂的扩展.可以配置在ESAPI.properties中使用的内容.例如:
ESAPI.Logger=org.owasp.esapi.reference.Log4JLogFactory
Run Code Online (Sandbox Code Playgroud)
avg*_*tvs 12
有没有办法在不将记录器更改为ESAPI的情况下修复此漏洞?
简而言之,是的.
TLDR:
首先要了解错误的严重性.主要关注的是伪造日志声明.假设你有这样的代码:
log.error( transactionId + " for user " + username + " was unsuccessful."
Run Code Online (Sandbox Code Playgroud)
如果任一变量受用户控制,则可以通过使用输入来注入错误的日志记录语句,\r\n for user foobar was successful\rn
从而允许它们伪造日志并覆盖其轨道.(好吧,在这个人为的情况下,只是让发现事情变得更难一点.)
第二种攻击方法更像是国际象棋移动.许多日志都是HTML格式的,可以在另一个程序中查看,对于这个例子,我们假装日志是要在浏览器中查看的HTML文件.现在我们注入<script src=”https://evilsite.com/hook.js” type=”text/javascript”></script>
,您将使用一个最有可能作为服务器管理员执行的开发框架来浏览浏览器......因为它怀疑CEO是否会阅读日志.现在真正的黑客可以开始了.
防御:
一个简单的防御是确保所有带有userinput的日志语句都使用显而易见的东西(例如'֎')来转义字符'\n'和'\ r',或者你可以执行ESAPI所做的操作并使用下划线进行转义.只要它一致,它就没关系,只要记住不要使用会让你在日志中迷惑的字符集.就像是userInput.replaceAll("\r", "?").replaceAll("\n", "?");
我还发现确保精确指定日志格式很有用......这意味着您确保对日志语句需要具有严格的标准并构建格式,以便更容易捕获恶意用户.所有程序员必须提交给派对并遵循格式!
为了防范HTML场景,我会使用[OWASP编码器项目] [1]
至于为什么建议实施ESAPI,它是一个经过实战考验的图书馆,但简而言之,这基本上就是我们所做的.看代码:
/**
* Log the message after optionally encoding any special characters that might be dangerous when viewed
* by an HTML based log viewer. Also encode any carriage returns and line feeds to prevent log
* injection attacks. This logs all the supplied parameters plus the user ID, user's source IP, a logging
* specific session ID, and the current date/time.
*
* It will only log the message if the current logging level is enabled, otherwise it will
* discard the message.
*
* @param level defines the set of recognized logging levels (TRACE, INFO, DEBUG, WARNING, ERROR, FATAL)
* @param type the type of the event (SECURITY SUCCESS, SECURITY FAILURE, EVENT SUCCESS, EVENT FAILURE)
* @param message the message to be logged
* @param throwable the {@code Throwable} from which to generate an exception stack trace.
*/
private void log(Level level, EventType type, String message, Throwable throwable) {
// Check to see if we need to log.
if (!isEnabledFor(level)) {
return;
}
// ensure there's something to log
if (message == null) {
message = "";
}
// ensure no CRLF injection into logs for forging records
String clean = message.replace('\n', '_').replace('\r', '_');
if (ESAPI.securityConfiguration().getLogEncodingRequired()) {
clean = ESAPI.encoder().encodeForHTML(message);
if (!message.equals(clean)) {
clean += " (Encoded)";
}
}
// log server, port, app name, module name -- server:80/app/module
StringBuilder appInfo = new StringBuilder();
if (ESAPI.currentRequest() != null && logServerIP) {
appInfo.append(ESAPI.currentRequest().getLocalAddr()).append(":").append(ESAPI.currentRequest().getLocalPort());
}
if (logAppName) {
appInfo.append("/").append(applicationName);
}
appInfo.append("/").append(getName());
//get the type text if it exists
String typeInfo = "";
if (type != null) {
typeInfo += type + " ";
}
// log the message
// Fix for https://code.google.com/p/owasp-esapi-java/issues/detail?id=268
// need to pass callerFQCN so the log is not generated as if it were always generated from this wrapper class
log(Log4JLogger.class.getName(), level, "[" + typeInfo + getUserInfo() + " -> " + appInfo + "] " + clean, throwable);
}
Run Code Online (Sandbox Code Playgroud)
见第398-453行.这就是ESAPI提供的所有逃避.我建议也要复制单元测试.
[免责声明]:我是ESAPI的项目联合负责人.
[1]:https://www.owasp.org/index.php/OWASP_Java_Encoder_Project并确保您在进入日志记录语句时对输入进行了正确编码 - 每一点都与您向用户发送输入时一样多.
小智 6
我是 Veracode 的新手,面对的是 CWE-117。我知道当您的 logger 语句有可能通过传入的恶意请求的参数值受到攻击时,Veracode 会引发此错误。因此,我们需要从 logger 语句中使用的变量中删除 /r 和 /n (CRLF)。
大多数新手会想知道应该使用什么方法从记录器语句中传递的变量中删除 CRLF。此外,有时 replaceAll() 将不起作用,因为它不是 Veracode 批准的方法。因此,这里是 Veracode 批准的处理 CWE 问题的方法的链接。https://help.veracode.com/reader/4EKhlLSMHm5jC8P8j3XccQ/IiF_rOE79ANbwnZwreSPGA
就我而言,我使用了上面链接中提到的 org.springframework.web.util.HtmlUtils.htmlEscape 并解决了问题。
private static final Logger LOG = LoggerFactory.getLogger(MemberController.class);
//problematic logger statement
LOG.info("brand {}, country {}",brand,country);
//Correct logger statement
LOG.info("brand {}, country {}",org.springframework.web.util.HtmlUtils.htmlEscape(brand),org.springframework.web.util.HtmlUtils.htmlEscape(country));
Run Code Online (Sandbox Code Playgroud)