mirror of
https://github.com/pocoproject/poco.git
synced 2025-07-04 17:40:01 +02:00
expose million laughs attack protection implemented by Expat 2.4
This commit is contained in:
parent
d95d9bd4a4
commit
cd6422fde3
@ -41,6 +41,14 @@ class XML_API SAXParser: public XMLReader
|
|||||||
/// The following proprietary extensions are supported:
|
/// The following proprietary extensions are supported:
|
||||||
/// * http://www.appinf.com/features/enable-partial-reads --
|
/// * http://www.appinf.com/features/enable-partial-reads --
|
||||||
/// see ParserEngine::setEnablePartialReads()
|
/// see ParserEngine::setEnablePartialReads()
|
||||||
|
/// * http://www.appinf.com/properties/bla-maximum-amplification
|
||||||
|
/// see ParserEngine::setBillionLaughsAttackProtectionMaximumAmplification();
|
||||||
|
/// argument must be a float >= 1.0 formatted as string;
|
||||||
|
/// property is set-only.
|
||||||
|
/// * http://www.appinf.com/properties/bla-activation-threshold
|
||||||
|
/// see ParserEngine::setBillionLaughsAttackProtectionActivationThreshold();
|
||||||
|
/// argument must be a 64-bit unsigned integer formatted as string;
|
||||||
|
/// property is set-only.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SAXParser();
|
SAXParser();
|
||||||
@ -86,6 +94,8 @@ public:
|
|||||||
void parseString(const std::string& xml);
|
void parseString(const std::string& xml);
|
||||||
|
|
||||||
static const XMLString FEATURE_PARTIAL_READS;
|
static const XMLString FEATURE_PARTIAL_READS;
|
||||||
|
static const XMLString PROPERTY_BLA_MAXIMUM_AMPLIFICATION;
|
||||||
|
static const XMLString PROPERTY_BLA_ACTIVATION_THRESHOLD;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setupParse();
|
void setupParse();
|
||||||
|
@ -163,6 +163,29 @@ public:
|
|||||||
/// Returns true if partial reads are enabled (see
|
/// Returns true if partial reads are enabled (see
|
||||||
/// setEnablePartialReads()), false otherwise.
|
/// setEnablePartialReads()), false otherwise.
|
||||||
|
|
||||||
|
void setBillionLaughsAttackProtectionMaximumAmplification(float maximumAmplificationFactor);
|
||||||
|
/// Sets the maximum tolerated amplification factor
|
||||||
|
/// for protection against Billion Laughs Attacks.
|
||||||
|
///
|
||||||
|
/// The amplification factor is calculated as:
|
||||||
|
/// amplification := (direct + indirect) / direct
|
||||||
|
/// while parsing, whereas:
|
||||||
|
/// - direct is the number of bytes read from the primary document in parsing and
|
||||||
|
/// - indirect is the number of bytes added by expanding entities and reading of
|
||||||
|
/// external DTD files, combined.
|
||||||
|
///
|
||||||
|
/// maximumAmplificationFactor must be non-NaN and greater than or equal to 1.0.
|
||||||
|
///
|
||||||
|
/// Requires an underlying Expat version >= 2.4.0.
|
||||||
|
|
||||||
|
void setBillionLaughsAttackProtectionActivationThreshold(Poco::UInt64 activationThresholdBytes);
|
||||||
|
/// Sets number of output bytes (including amplification from entity expansion and reading DTD files)
|
||||||
|
/// needed to activate protection against Billion Laughs Attacks.
|
||||||
|
///
|
||||||
|
/// Defaults to 8 MiB.
|
||||||
|
///
|
||||||
|
/// Requires an underlying Expat version >= 2.4.0.
|
||||||
|
|
||||||
void parse(InputSource* pInputSource);
|
void parse(InputSource* pInputSource);
|
||||||
/// Parse an XML document from the given InputSource.
|
/// Parse an XML document from the given InputSource.
|
||||||
|
|
||||||
@ -272,6 +295,9 @@ private:
|
|||||||
LexicalHandler* _pLexicalHandler;
|
LexicalHandler* _pLexicalHandler;
|
||||||
ErrorHandler* _pErrorHandler;
|
ErrorHandler* _pErrorHandler;
|
||||||
|
|
||||||
|
float _maximumAmplificationFactor;
|
||||||
|
Poco::UInt64 _activationThresholdBytes;
|
||||||
|
|
||||||
static const int PARSE_BUFFER_SIZE;
|
static const int PARSE_BUFFER_SIZE;
|
||||||
static const XMLString EMPTY_STRING;
|
static const XMLString EMPTY_STRING;
|
||||||
};
|
};
|
||||||
|
@ -97,7 +97,9 @@ ParserEngine::ParserEngine():
|
|||||||
_pDeclHandler(0),
|
_pDeclHandler(0),
|
||||||
_pContentHandler(0),
|
_pContentHandler(0),
|
||||||
_pLexicalHandler(0),
|
_pLexicalHandler(0),
|
||||||
_pErrorHandler(0)
|
_pErrorHandler(0),
|
||||||
|
_maximumAmplificationFactor(0.0),
|
||||||
|
_activationThresholdBytes(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +119,9 @@ ParserEngine::ParserEngine(const XMLString& encoding):
|
|||||||
_pDeclHandler(0),
|
_pDeclHandler(0),
|
||||||
_pContentHandler(0),
|
_pContentHandler(0),
|
||||||
_pLexicalHandler(0),
|
_pLexicalHandler(0),
|
||||||
_pErrorHandler(0)
|
_pErrorHandler(0),
|
||||||
|
_maximumAmplificationFactor(0.0),
|
||||||
|
_activationThresholdBytes(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,6 +222,18 @@ void ParserEngine::setEnablePartialReads(bool flag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ParserEngine::setBillionLaughsAttackProtectionMaximumAmplification(float maximumAmplificationFactor)
|
||||||
|
{
|
||||||
|
_maximumAmplificationFactor = maximumAmplificationFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ParserEngine::setBillionLaughsAttackProtectionActivationThreshold(Poco::UInt64 activationThresholdBytes)
|
||||||
|
{
|
||||||
|
_activationThresholdBytes = activationThresholdBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ParserEngine::parse(InputSource* pInputSource)
|
void ParserEngine::parse(InputSource* pInputSource)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
@ -487,6 +503,17 @@ void ParserEngine::init()
|
|||||||
XML_SetSkippedEntityHandler(_parser, handleSkippedEntity);
|
XML_SetSkippedEntityHandler(_parser, handleSkippedEntity);
|
||||||
XML_SetParamEntityParsing(_parser, _externalParameterEntities ? XML_PARAM_ENTITY_PARSING_ALWAYS : XML_PARAM_ENTITY_PARSING_NEVER);
|
XML_SetParamEntityParsing(_parser, _externalParameterEntities ? XML_PARAM_ENTITY_PARSING_ALWAYS : XML_PARAM_ENTITY_PARSING_NEVER);
|
||||||
XML_SetUnknownEncodingHandler(_parser, handleUnknownEncoding, this);
|
XML_SetUnknownEncodingHandler(_parser, handleUnknownEncoding, this);
|
||||||
|
|
||||||
|
#if XML_MAJOR_VERSION > 2 || (XML_MAJOR_VERSION == 2 && XML_MINOR_VERSION >= 4)
|
||||||
|
if (_maximumAmplificationFactor > 1.0)
|
||||||
|
{
|
||||||
|
XML_SetBillionLaughsAttackProtectionMaximumAmplification(_parser, _maximumAmplificationFactor);
|
||||||
|
}
|
||||||
|
if (_activationThresholdBytes > 0)
|
||||||
|
{
|
||||||
|
XML_SetBillionLaughsAttackProtectionActivationThreshold(_parser, _activationThresholdBytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -570,6 +597,26 @@ void ParserEngine::handleError(int errorNo)
|
|||||||
throw SAXParseException("Parsing finished", locator());
|
throw SAXParseException("Parsing finished", locator());
|
||||||
case XML_ERROR_SUSPEND_PE:
|
case XML_ERROR_SUSPEND_PE:
|
||||||
throw SAXParseException("Cannot suspend in external parameter entity", locator());
|
throw SAXParseException("Cannot suspend in external parameter entity", locator());
|
||||||
|
#if XML_MAJOR_VERSION >= 2
|
||||||
|
case XML_ERROR_RESERVED_PREFIX_XML:
|
||||||
|
throw SAXParseException("Reserved prefix 'xml' must not be undeclared or bound to another namespace name", locator());
|
||||||
|
case XML_ERROR_RESERVED_PREFIX_XMLNS:
|
||||||
|
throw SAXParseException("Reserved prefix 'xmlns' must not be declared or undeclared", locator());
|
||||||
|
case XML_ERROR_RESERVED_NAMESPACE_URI:
|
||||||
|
throw SAXParseException("Prefix must not be bound to one of the reserved namespace names", locator());
|
||||||
|
#if XML_MAJOR_VERSION > 2 || XML_MINOR_VERSION >= 1
|
||||||
|
case XML_ERROR_INVALID_ARGUMENT:
|
||||||
|
throw SAXParseException("Invalid argument", locator());
|
||||||
|
#endif
|
||||||
|
#if XML_MAJOR_VERSION > 2 || XML_MINOR_VERSION >= 3
|
||||||
|
case XML_ERROR_NO_BUFFER:
|
||||||
|
throw SAXParseException("Internal error: a successful prior call to function XML_GetBuffer is required", locator());
|
||||||
|
#endif
|
||||||
|
#if XML_MAJOR_VERSION > 2 || XML_MINOR_VERSION >= 4
|
||||||
|
case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
|
||||||
|
throw SAXParseException("Limit on input amplification factor (from DTD and entities) breached", locator());
|
||||||
|
#endif
|
||||||
|
#endif // XML_MAJOR_VERSION
|
||||||
}
|
}
|
||||||
throw XMLException("Unknown Expat error code");
|
throw XMLException("Unknown Expat error code");
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "Poco/SAX/EntityResolverImpl.h"
|
#include "Poco/SAX/EntityResolverImpl.h"
|
||||||
#include "Poco/SAX/InputSource.h"
|
#include "Poco/SAX/InputSource.h"
|
||||||
#include "Poco/XML/NamespaceStrategy.h"
|
#include "Poco/XML/NamespaceStrategy.h"
|
||||||
|
#include "Poco/NumberParser.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
@ -25,6 +26,8 @@ namespace XML {
|
|||||||
|
|
||||||
|
|
||||||
const XMLString SAXParser::FEATURE_PARTIAL_READS = toXMLString("http://www.appinf.com/features/enable-partial-reads");
|
const XMLString SAXParser::FEATURE_PARTIAL_READS = toXMLString("http://www.appinf.com/features/enable-partial-reads");
|
||||||
|
const XMLString SAXParser::PROPERTY_BLA_MAXIMUM_AMPLIFICATION = toXMLString("http://www.appinf.com/properties/bla-maximum-amplification");
|
||||||
|
const XMLString SAXParser::PROPERTY_BLA_ACTIVATION_THRESHOLD = toXMLString("http://www.appinf.com/properties/bla-activation-threshold");
|
||||||
|
|
||||||
|
|
||||||
SAXParser::SAXParser():
|
SAXParser::SAXParser():
|
||||||
@ -153,6 +156,10 @@ void SAXParser::setProperty(const XMLString& propertyId, const XMLString& value)
|
|||||||
{
|
{
|
||||||
if (propertyId == XMLReader::PROPERTY_DECLARATION_HANDLER || propertyId == XMLReader::PROPERTY_LEXICAL_HANDLER)
|
if (propertyId == XMLReader::PROPERTY_DECLARATION_HANDLER || propertyId == XMLReader::PROPERTY_LEXICAL_HANDLER)
|
||||||
throw SAXNotSupportedException(std::string("property does not take a string value: ") + fromXMLString(propertyId));
|
throw SAXNotSupportedException(std::string("property does not take a string value: ") + fromXMLString(propertyId));
|
||||||
|
else if (propertyId == PROPERTY_BLA_MAXIMUM_AMPLIFICATION)
|
||||||
|
_engine.setBillionLaughsAttackProtectionMaximumAmplification(static_cast<float>(Poco::NumberParser::parseFloat(value)));
|
||||||
|
else if (propertyId == PROPERTY_BLA_ACTIVATION_THRESHOLD)
|
||||||
|
_engine.setBillionLaughsAttackProtectionActivationThreshold(Poco::NumberParser::parseUnsigned64(value));
|
||||||
else
|
else
|
||||||
throw SAXNotRecognizedException(fromXMLString(propertyId));
|
throw SAXNotRecognizedException(fromXMLString(propertyId));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user