summaryrefslogtreecommitdiff
path: root/include/openbmc_dbus_rest.hpp
diff options
context:
space:
mode:
authorEd Tanous <edtanous@google.com>2022-02-08 14:24:30 +0300
committerEd Tanous <ed@tanous.net>2023-02-17 20:01:21 +0300
commit1aa0c2b84be62a20d8c37a11ad877e0a8a48c69d (patch)
tree60a3f45204bcc8947f25db6e64cc3cd5d01f0648 /include/openbmc_dbus_rest.hpp
parent6177a301de5cefdb4a31601ec2d899f4309fc6c2 (diff)
downloadbmcweb-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.hpp49
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);