mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 08:46:46 +00:00
refactor: Limit JSON array size (#63)
This commit is contained in:
@@ -26,6 +26,13 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Maximum JSON object nesting depth permitted during parsing. */
|
||||
inline constexpr std::size_t maxSTParsedJSONDepth = 64;
|
||||
|
||||
/** Maximum number of elements permitted in any JSON array field during parsing.
|
||||
Requests exceeding this limit are rejected with an invalidParams error. */
|
||||
inline constexpr std::size_t maxSTParsedJSONArraySize = 512;
|
||||
|
||||
/** Holds the serialized result of parsing an input JSON object.
|
||||
This does validation and checking on the provided JSON.
|
||||
*/
|
||||
|
||||
@@ -160,6 +160,16 @@ array_expected(std::string const& object, std::string const& field)
|
||||
"Field '" + make_name(object, field) + "' must be a JSON array.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
array_too_big(std::string const& object, std::string const& field)
|
||||
{
|
||||
return RPC::make_error(
|
||||
rpcINVALID_PARAMS,
|
||||
"Field '" + make_name(object, field) +
|
||||
"' exceeds allowed JSON array size of " +
|
||||
std::to_string(maxSTParsedJSONArraySize) + " elements per field.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
string_expected(std::string const& object, std::string const& field)
|
||||
{
|
||||
@@ -743,6 +753,12 @@ parseLeaf(
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (not value.isNull() and value.size() > maxSTParsedJSONArraySize)
|
||||
{
|
||||
error = array_too_big(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
STVector256 tail(field);
|
||||
@@ -770,6 +786,12 @@ parseLeaf(
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (not value.isNull() and value.size() > maxSTParsedJSONArraySize)
|
||||
{
|
||||
error = array_too_big(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
STPathSet tail(field);
|
||||
@@ -786,6 +808,15 @@ parseLeaf(
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (not value[i].isNull() and
|
||||
value[i].size() > maxSTParsedJSONArraySize)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << fieldName << "[" << i << "]";
|
||||
error = array_too_big(json_name, ss.str());
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (Json::UInt j = 0; value[i].isValidIndex(j); ++j)
|
||||
{
|
||||
std::stringstream ss;
|
||||
@@ -980,8 +1011,6 @@ parseLeaf(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int const maxDepth = 64;
|
||||
|
||||
// Forward declaration since parseObject() and parseArray() call each other.
|
||||
static std::optional<detail::STVar>
|
||||
parseArray(
|
||||
@@ -1005,7 +1034,7 @@ parseObject(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (depth > maxDepth)
|
||||
if (depth > maxSTParsedJSONDepth)
|
||||
{
|
||||
error = too_deep(json_name);
|
||||
return std::nullopt;
|
||||
@@ -1018,7 +1047,6 @@ parseObject(
|
||||
for (auto const& fieldName : json.getMemberNames())
|
||||
{
|
||||
Json::Value const& value = json[fieldName];
|
||||
|
||||
auto const& field = SField::getField(fieldName);
|
||||
|
||||
if (field == sfInvalid)
|
||||
@@ -1128,12 +1156,18 @@ parseArray(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (depth > maxDepth)
|
||||
if (depth > maxSTParsedJSONDepth)
|
||||
{
|
||||
error = too_deep(json_name);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (not json.isNull() and json.size() > maxSTParsedJSONArraySize)
|
||||
{
|
||||
error = array_too_big(json_name, "");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
STArray tail(inName);
|
||||
@@ -1151,10 +1185,9 @@ parseArray(
|
||||
}
|
||||
|
||||
// TODO: There doesn't seem to be a nice way to get just the
|
||||
// first/only key in an object without copying all keys into
|
||||
// a vector
|
||||
// first/only key in an object without copying all keys into a
|
||||
// vector
|
||||
std::string const objectName(json[i].getMemberNames()[0]);
|
||||
;
|
||||
auto const& nameField(SField::getField(objectName));
|
||||
|
||||
if (nameField == sfInvalid)
|
||||
|
||||
Reference in New Issue
Block a user