fix(net): cap market and bootstrap HTTP response bodies
Several HTTP fetches read a remote body into memory without a tight bound. The price and exchange-ticker calls shared one large 16 MiB metadata cap, and the bootstrap checksum download had no size limit at all, so a hostile or MITM'd server streaming an unbounded (and Content-Length-free) response could grow memory far past anything these endpoints legitimately return. - The HTTP GET helper now takes a per-call byte cap and redirect limit. The write callback refuses bytes past the cap, which aborts the transfer, and the same value is set as curl's max file size. - The price call is capped at 256 KiB and the ticker list at 2 MiB, each sized to its real payload rather than the shared default. - The bootstrap checksum fetch caps its body at 64 KiB in both the write callback and curl's max file size. Tests cover the sink accept/abort boundary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+6
-2
@@ -3201,7 +3201,9 @@ void App::refreshPrice()
|
||||
NetworkRefreshService::PriceHttpResult result;
|
||||
try {
|
||||
const char* const url = "https://api.coingecko.com/api/v3/simple/price?ids=dragonx-2&vs_currencies=usd,btc&include_24hr_change=true&include_24hr_vol=true&include_market_cap=true";
|
||||
util::HttpGetResult r = util::httpGet(url, "[price]", marketHttp(&http_cancel_, 10));
|
||||
util::HttpGetOptions priceOpt = marketHttp(&http_cancel_, 10);
|
||||
priceOpt.maxBytes = 256 * 1024;
|
||||
util::HttpGetResult r = util::httpGet(url, "[price]", priceOpt);
|
||||
NetworkRefreshService::PriceHttpResponse response{
|
||||
r.transportOk, r.httpStatus, std::move(r.body), r.error};
|
||||
result = NetworkRefreshService::parsePriceHttpResponse(response, std::time(nullptr));
|
||||
@@ -3433,9 +3435,11 @@ void App::refreshExchanges()
|
||||
|
||||
http_worker_->post([this]() -> rpc::RPCWorker::MainCb {
|
||||
// httpGetString verifies TLS, caps the response size and returns "" on any failure.
|
||||
util::HttpGetOptions tickersOpt = marketHttp(&http_cancel_, 12);
|
||||
tickersOpt.maxBytes = 2 * 1024 * 1024;
|
||||
const std::string body = util::httpGetString(
|
||||
"https://api.coingecko.com/api/v3/coins/dragonx-2/tickers", "[tickers]",
|
||||
marketHttp(&http_cancel_, 12));
|
||||
tickersOpt);
|
||||
std::vector<data::ExchangeInfo> exchanges;
|
||||
if (!body.empty()) {
|
||||
try { exchanges = data::parseCoinGeckoTickers(body); } catch (...) {}
|
||||
|
||||
Reference in New Issue
Block a user