diff options
author | Ed Tanous <edtanous@google.com> | 2022-02-08 14:24:30 +0300 |
---|---|---|
committer | Ed Tanous <ed@tanous.net> | 2023-02-17 20:01:21 +0300 |
commit | 1aa0c2b84be62a20d8c37a11ad877e0a8a48c69d (patch) | |
tree | 60a3f45204bcc8947f25db6e64cc3cd5d01f0648 /include/openbmc_dbus_rest.hpp | |
parent | 6177a301de5cefdb4a31601ec2d899f4309fc6c2 (diff) | |
download | bmcweb-1aa0c2b84be62a20d8c37a11ad877e0a8a48c69d.tar.xz |
Add option for validating content-type header
For systems implementing to the OWASP security guidelines[1] (of which all
should ideally) we should be checking the content-type header all times
that we parse a request as JSON.
This commit adds an option for parsing content-type, and sets a default
of "must get content-type". Ideally this would not be a breaking
change, but given the number of guides and scripts that omit the content
type, it seems worthwhile to add a trapdoor, such that people can opt
into their own model on how they would like to see this checking work.
Tested:
```
curl --insecure -H "Content-Type: application/json" -X POST -D headers.txt https://${bmc}/redfish/v1/SessionService/Sessions -d '{"UserName":"root", "Password":"0penBmc"}'
```
Succeeds.
Removing Content-Type argument causes bmc to return
Base.1.13.0.UnrecognizedRequestBody.
[1] cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html
Change-Id: Iaa47dd563b40036ff2fc2cacb70d941fd8853038
Signed-off-by: Ed Tanous <edtanous@google.com>
Diffstat (limited to 'include/openbmc_dbus_rest.hpp')
-rw-r--r-- | include/openbmc_dbus_rest.hpp | 49 |
1 files changed, 38 insertions, 11 deletions
diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp index 2665b2e6d1..9bf968a40d 100644 --- a/include/openbmc_dbus_rest.hpp +++ b/include/openbmc_dbus_rest.hpp @@ -20,6 +20,7 @@ #include "http_request.hpp" #include "http_response.hpp" #include "logging.hpp" +#include "parsing.hpp" #include "routing.hpp" #include "str_utility.hpp" @@ -80,6 +81,7 @@ const constexpr char* notFoundMsg = "404 Not Found"; const constexpr char* badReqMsg = "400 Bad Request"; const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed"; const constexpr char* forbiddenMsg = "403 Forbidden"; +const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type"; const constexpr char* methodFailedMsg = "500 Method Call Failed"; const constexpr char* methodOutputFailedMsg = "500 Method Output Error"; const constexpr char* notFoundDesc = @@ -87,6 +89,8 @@ const constexpr char* notFoundDesc = const constexpr char* propNotFoundDesc = "The specified property cannot be found"; const constexpr char* noJsonDesc = "No JSON object could be decoded"; +const constexpr char* invalidContentType = + "Content-type header is missing or invalid"; const constexpr char* methodNotFoundDesc = "The specified method cannot be found"; const constexpr char* methodNotAllowedDesc = "Method not allowed"; @@ -1538,10 +1542,17 @@ inline void handleAction(const crow::Request& req, { BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method " << methodName; - nlohmann::json requestDbusData = - nlohmann::json::parse(req.body, nullptr, false); + nlohmann::json requestDbusData; - if (requestDbusData.is_discarded()) + JsonParseResult ret = parseRequestAsJson(req, requestDbusData); + if (ret == JsonParseResult::BadContentType) + { + setErrorResponse(asyncResp->res, + boost::beast::http::status::unsupported_media_type, + invalidContentType, unsupportedMediaMsg); + return; + } + if (ret != JsonParseResult::Success) { setErrorResponse(asyncResp->res, boost::beast::http::status::bad_request, noJsonDesc, @@ -1838,11 +1849,18 @@ inline void handlePut(const crow::Request& req, forbiddenResDesc, forbiddenMsg); return; } + nlohmann::json requestDbusData; - nlohmann::json requestDbusData = - nlohmann::json::parse(req.body, nullptr, false); + JsonParseResult ret = parseRequestAsJson(req, requestDbusData); + if (ret == JsonParseResult::BadContentType) + { + setErrorResponse(asyncResp->res, + boost::beast::http::status::unsupported_media_type, + invalidContentType, unsupportedMediaMsg); + return; + } - if (requestDbusData.is_discarded()) + if (ret != JsonParseResult::Success) { setErrorResponse(asyncResp->res, boost::beast::http::status::bad_request, noJsonDesc, @@ -2376,14 +2394,23 @@ inline void return; } - nlohmann::json requestDbusData = - nlohmann::json::parse(req.body, nullptr, false); - - if (requestDbusData.is_discarded()) + nlohmann::json requestDbusData; + JsonParseResult ret = parseRequestAsJson(req, requestDbusData); + if (ret == JsonParseResult::BadContentType) { - asyncResp->res.result(boost::beast::http::status::bad_request); + setErrorResponse(asyncResp->res, + boost::beast::http::status::unsupported_media_type, + invalidContentType, unsupportedMediaMsg); + return; + } + if (ret != JsonParseResult::Success) + { + setErrorResponse(asyncResp->res, + boost::beast::http::status::bad_request, + noJsonDesc, badReqMsg); return; } + if (!requestDbusData.is_array()) { asyncResp->res.result(boost::beast::http::status::bad_request); |