Mitigation Strategy: Use Iterative Parsing (kParseIterativeFlag)
- Locate all instances where
rapidjson::Document::Parse()
or similar parsing functions (e.g.,ParseStream()
) are called. - Modify the parsing call to include the
kParseIterativeFlag
. This flag changes the parsing algorithm from recursive descent to an iterative approach, eliminating stack overflow risk from deep nesting. - Example: Change
document.Parse(json_string);
todocument.Parse<rapidjson::kParseIterativeFlag>(json_string);
. - Thoroughly test the application after this change.
-
Threats Mitigated:
- Stack Exhaustion (Denial of Service) due to Deeply Nested JSON: (Severity: High) - Prevents application crashes from deeply nested JSON.
- Resource Exhaustion (Denial of Service): (Severity: High) - Reduces memory footprint and processing time for deeply nested JSON.
-
Impact:
- Stack Exhaustion: Risk reduced from High to Negligible.
- Resource Exhaustion: Risk reduced from High to Low.
-
Currently Implemented:
- Yes/No/Partially: (Replace with the actual status)
- Location(s): (e.g.,
src/json_parser.cpp:123
,src/api/handler.cpp:456
)
-
Missing Implementation:
- Location(s): (e.g.,
src/legacy_parser.cpp:789
)
- Location(s): (e.g.,
Mitigation Strategy: Use Safe Integer Accessors and Check Bounds
- Identify locations where integer values are retrieved using RapidJSON.
- Use the largest appropriate integer type accessor (e.g.,
GetInt64()
,GetUint64()
) instead ofGetInt()
if large numbers are possible. - After retrieving the integer with RapidJSON, perform explicit bounds checking against application-defined
MIN_ALLOWED_VALUE
andMAX_ALLOWED_VALUE
. - Handle out-of-bounds errors appropriately.
- Example:
if (value.IsInt()) { // Or IsInt64(), IsUint64() long long num = value.GetInt64(); // Use appropriate type if (num < MIN_ALLOWED_VALUE || num > MAX_ALLOWED_VALUE) { // Handle the error } else { // Use 'num' } }
-
Threats Mitigated:
- Integer Overflow/Underflow: (Severity: High)
- Unexpected Behavior: (Severity: Medium)
-
Impact:
- Integer Overflow/Underflow: Risk reduced from High to Negligible.
- Unexpected Behavior: Risk reduced from Medium to Low.
-
Currently Implemented:
- Yes/No/Partially: (Replace with the actual status)
- Location(s): (e.g.,
src/data_processor.cpp:200
)
-
Missing Implementation:
- Location(s): (e.g.,
src/legacy_module.cpp:110
)
- Location(s): (e.g.,
Mitigation Strategy: Validate Floating-Point Values and Check for NaN/Inf
- Identify locations where floating-point values are retrieved.
- Use
IsDouble()
to check the type. - After retrieving with
GetDouble()
, check forNaN
andInf
usingstd::isnan()
andstd::isinf()
. - Check if the value is within application-defined
MIN_ALLOWED_VALUE
andMAX_ALLOWED_VALUE
. - Handle errors (NaN, Inf, out-of-bounds) appropriately.
- Example:
if (value.IsDouble()) { double num = value.GetDouble(); if (std::isnan(num) || std::isinf(num) || num < MIN_ALLOWED_VALUE || num > MAX_ALLOWED_VALUE) { // Handle the error } else { // Use 'num' } }
-
Threats Mitigated:
- Floating-Point Parsing Issues: (Severity: Medium)
- Denial of Service (DoS): (Severity: Medium)
- Unexpected Behavior: (Severity: Medium)
-
Impact:
- Floating-Point Parsing Issues: Risk reduced from Medium to Low.
- Denial of Service: Risk reduced from Medium to Low.
- Unexpected Behavior: Risk reduced from Medium to Low.
-
Currently Implemented:
- Yes/No/Partially: (Replace with the actual status)
- Location(s): (e.g.,
src/calculation_engine.cpp:80
)
-
Missing Implementation:
- Location(s): (e.g.,
src/old_data_format.cpp:45
)
- Location(s): (e.g.,
Mitigation Strategy: Always Check Data Types
- Before accessing any value, use RapidJSON's type-checking methods (e.g.,
IsString()
,IsObject()
,IsArray()
,IsInt()
,IsDouble()
,IsNull()
,IsBool()
). - Use the appropriate accessor method based on the expected type.
- Handle type mismatches appropriately.
- Example:
if (value.HasMember("data") && value["data"].IsArray()) { const rapidjson::Value& dataArray = value["data"].GetArray(); // Process the array } else { // Handle the error }
-
Threats Mitigated:
- Unexpected Data Types: (Severity: High)
- Type Confusion Vulnerabilities: (Severity: Medium)
-
Impact:
- Unexpected Data Types: Risk reduced from High to Negligible.
- Type Confusion Vulnerabilities: Risk reduced from Medium to Low.
-
Currently Implemented:
- Yes/No/Partially: (Replace with the actual status)
- Location(s): (e.g.,
src/json_utils.cpp:30
)
-
Missing Implementation:
- Location(s): (e.g.,
src/quick_and_dirty_parser.cpp:25
)
- Location(s): (e.g.,
Mitigation Strategy: Use GetStringLength()
for String Handling
- Identify locations where string values are retrieved.
- Use
GetString()
to get the string pointer andGetStringLength()
to get the actual length. - Use the returned length. Do not rely on
strlen()
. - For
std::string
, use:std::string(str, len);
. - Example:
if (value.IsString()) { const char* str = value.GetString(); rapidjson::SizeType len = value.GetStringLength(); std::string safe_string(str, len); // Use the safe string // ... or work directly with 'str' and 'len' ... }
-
Threats Mitigated:
- Null Character Injection: (Severity: High)
- Buffer Overflows: (Severity: High)
-
Impact:
- Null Character Injection: Risk reduced from High to Negligible.
- Buffer Overflows: Risk reduced from High to Low.
-
Currently Implemented:
- Yes/No/Partially: (Replace with the actual status)
- Location(s): (e.g.,
src/string_processor.cpp:60
)
-
Missing Implementation:
- Location(s): (e.g.,
src/legacy_string_handling.cpp:85
)
- Location(s): (e.g.,
Mitigation Strategy: Use a Custom Allocator
- Create a custom allocator class inheriting from
rapidjson::Allocator
. - Override
Malloc
andRealloc
to track memory usage and enforce limits. - In
Malloc
andRealloc
, check if the requested allocation exceeds a limit. If so, returnnullptr
. - When creating the
rapidjson::Document
, pass an instance of your custom allocator. - Example:
class MyAllocator : public rapidjson::Allocator { public: void* Malloc(size_t size) { if (totalAllocated + size > MAX_ALLOCATION_SIZE) { return nullptr; // Allocation failed } void* ptr = malloc(size); if (ptr) { totalAllocated += size; } return ptr; } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { // Similar logic to Malloc, handling reallocation if (totalAllocated - originalSize + newSize > MAX_ALLOCATION_SIZE) { return nullptr; } void* ptr = realloc(originalPtr, newSize); if(ptr) { totalAllocated += (newSize - originalSize); } return ptr; } void Free(void* ptr) { // You might want to track the size here for more accurate accounting if (ptr) { //totalAllocated -= size; // Need to know the size of the allocated block } free(ptr); } private: size_t totalAllocated = 0; static constexpr size_t MAX_ALLOCATION_SIZE = 1024 * 1024 * 10; // 10MB limit }; // ... later ... MyAllocator allocator; rapidjson::Document document(&allocator);
- Check for allocation errors after parsing:
if (document.HasParseError() && document.GetParseError() == rapidjson::kParseErrorDocumentEmpty) { // Handle potential memory allocation failure }
-
Threats Mitigated:
- Memory Exhaustion (Denial of Service): (Severity: High) - Limits memory RapidJSON can allocate.
-
Impact:
- Memory Exhaustion: Risk reduced from High to Low.
-
Currently Implemented:
- Yes/No/Partially: (Replace with the actual status)
- Location(s): (e.g.,
src/memory_management.cpp
,src/json_parser.cpp
)
-
Missing Implementation:
- Location(s): (If not implemented, describe where it should be implemented.)