V5333. OWASP. Possible insecure deserialization vulnerability. Potentially tainted data is used to create an object during deserialization.

Анализатор обнаружил, что для десериализации объекта через стандартные Java-механизмы используются данные, полученные из внешнего источника. Это может подвергнуть приложение уязвимости.

Атаки, связанные с десериализацией данных извне, выделены в отдельную категорию OWASP Top Ten Application Security Risks:

У атак, осуществляемых через десериализацию данных извне, могут быть различные цели и варианты реализации:

Существуют советы, следование которым поможет уменьшить вероятность возникновения одной из вышеперечисленных проблем. Главный из них — не предоставлять пользователям возможность отправлять приложению данные для десериализации. Если же это необходимо, следует помнить, что:

В случае использования стандартного Java-интерфейса для десериализации один из вариантов защиты от потенциальных проблем — смотреть, какого типа объект десериализуется. Важно помнить, что делать это нужно до того, как объект восстановлен.

Пример небезопасной конфигурации:

public void notSecure(HttpServletRequest req, 
                      HttpServletResponse res) throws .... {
    ServletInputStream servletIS = req.getInputStream();
    ObjectInputStream  objectIS  = new ObjectInputStream(servletIS); // <=
    Object object = objectIS.readObject();
}

Пример конфигурации с проверкой:

class SecureObjectInputStream extends ObjectInputStream {
  public SecureObjectInputStream(InputStream in) throws IOException {
    super(in);
  }

  @Override
  protected Class<?> resolveClass(ObjectStreamClass osc) throws .... {
    List<String> allowedClasses = new ArrayList<>();
    allowedClasses.add(AllowedClass1.class.getName());
    allowedClasses.add(AllowedClass2.class.getName());
    if (!allowedClasses.contains(osc.getName())) {
      throw new InvalidClassException("Unauthorized deserialization", 
                                      osc.getName());
    }
    return super.resolveClass(osc);
  }
}

....

public void withCheck(HttpServletRequest req, 
                      HttpServletResponse res) throws .... {
  ServletInputStream servletIS = req.getInputStream();
  ObjectInputStream objectIS   = new SecureObjectInputStream(servletIS);
  Object object = objectIS.readObject();
}

В исправленном примере создан класс SecureObjectInputStream. Он является наследником ObjectInputStream. В нём переопределён метод resolveClass, что позволяет проверить, какого типа объект будет десериализован. Выполняется этот метод до десериализации объекта. Если объект не находится в перечне тех, что мы хотим десериализовать, выбрасывается исключение. Это позволит не допустить десериализацию небезопасного объекта, чьё внутреннее содержимое может навредить приложению.

Полезные ссылки:

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки непроверенного использования чувствительных данных (ввода пользователя, файлов, сети и пр.).

Данная диагностика классифицируется как: