mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 13:26:01 +03:00
Adds support to JSON request body parser
This commit is contained in:
parent
2477470607
commit
90adb53935
@ -222,3 +222,5 @@ TESTS+=test/test-cases/regression/variable-STATUS.json
|
||||
TESTS+=test/test-cases/regression/variable-RESPONSE_PROTOCOL.json
|
||||
TESTS+=test/test-cases/regression/variable-SERVER_NAME.json
|
||||
TESTS+=test/test-cases/regression/operator-UnconditionalMatch.json
|
||||
TESTS+=test/test-cases/regression/request-body-parser-json.json
|
||||
|
||||
|
@ -76,6 +76,7 @@ class Action;
|
||||
}
|
||||
namespace RequestBodyProcessor {
|
||||
class XML;
|
||||
class JSON;
|
||||
}
|
||||
namespace operators {
|
||||
class Operator;
|
||||
@ -337,6 +338,7 @@ class Transaction {
|
||||
std::list<std::string> m_matched;
|
||||
|
||||
RequestBodyProcessor::XML *m_xml;
|
||||
RequestBodyProcessor::JSON *m_json;
|
||||
|
||||
private:
|
||||
std::string *m_ARGScombinedSizeStr;
|
||||
|
@ -83,6 +83,7 @@ ACTIONS = \
|
||||
actions/capture.cc \
|
||||
actions/chain.cc \
|
||||
actions/ctl_audit_log_parts.cc \
|
||||
actions/ctl_request_body_processor_json.cc \
|
||||
actions/ctl_request_body_processor_xml.cc \
|
||||
actions/init_col.cc \
|
||||
actions/deny.cc \
|
||||
@ -202,7 +203,8 @@ COLLECTION = \
|
||||
|
||||
BODY_PROCESSORS = \
|
||||
request_body_processor/multipart.cc \
|
||||
request_body_processor/xml.cc
|
||||
request_body_processor/xml.cc \
|
||||
request_body_processor/json.cc
|
||||
|
||||
|
||||
libmodsecurity_la_SOURCES = \
|
||||
|
37
src/actions/ctl_request_body_processor_json.cc
Normal file
37
src/actions/ctl_request_body_processor_json.cc
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* ModSecurity, http://www.modsecurity.org/
|
||||
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "actions/ctl_request_body_processor_json.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "modsecurity/transaction.h"
|
||||
|
||||
namespace modsecurity {
|
||||
namespace actions {
|
||||
|
||||
|
||||
bool CtlRequestBodyProcessorJSON::evaluate(Rule *rule,
|
||||
Transaction *transaction) {
|
||||
transaction->m_requestBodyProcessor = Transaction::JSONRequestBody;
|
||||
transaction->m_collections.store("REQBODY_PROCESSOR", "JSON");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace actions
|
||||
} // namespace modsecurity
|
39
src/actions/ctl_request_body_processor_json.h
Normal file
39
src/actions/ctl_request_body_processor_json.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* ModSecurity, http://www.modsecurity.org/
|
||||
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "actions/action.h"
|
||||
#include "modsecurity/transaction.h"
|
||||
|
||||
#ifndef SRC_ACTIONS_CTL_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
#define SRC_ACTIONS_CTL_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
|
||||
namespace modsecurity {
|
||||
namespace actions {
|
||||
|
||||
|
||||
class CtlRequestBodyProcessorJSON : public Action {
|
||||
public:
|
||||
explicit CtlRequestBodyProcessorJSON(std::string action)
|
||||
: Action(action, RunTimeOnlyIfMatchKind) { }
|
||||
|
||||
bool evaluate(Rule *rule, Transaction *transaction) override;
|
||||
};
|
||||
|
||||
} // namespace actions
|
||||
} // namespace modsecurity
|
||||
|
||||
#endif // SRC_ACTIONS_CTL_REQUEST_BODY_PROCESSOR_JSON_H_
|
@ -23,6 +23,7 @@ class Driver;
|
||||
#include "actions/action.h"
|
||||
#include "actions/audit_log.h"
|
||||
#include "actions/ctl_audit_log_parts.h"
|
||||
#include "actions/ctl_request_body_processor_json.h"
|
||||
#include "actions/ctl_request_body_processor_xml.h"
|
||||
#include "actions/init_col.h"
|
||||
#include "actions/set_sid.h"
|
||||
@ -73,6 +74,7 @@ using modsecurity::actions::Accuracy;
|
||||
using modsecurity::actions::Action;
|
||||
using modsecurity::actions::CtlAuditLogParts;
|
||||
using modsecurity::actions::CtlRequestBodyProcessorXML;
|
||||
using modsecurity::actions::CtlRequestBodyProcessorJSON;
|
||||
using modsecurity::actions::InitCol;
|
||||
using modsecurity::actions::SetSID;
|
||||
using modsecurity::actions::SetUID;
|
||||
@ -1184,8 +1186,7 @@ act:
|
||||
}
|
||||
| ACTION_CTL_BDY_JSON
|
||||
{
|
||||
/* not ready yet. */
|
||||
$$ = Action::instantiate($1);
|
||||
$$ = new modsecurity::actions::CtlRequestBodyProcessorJSON($1);
|
||||
}
|
||||
| ACTION_CTL_AUDIT_LOG_PARTS
|
||||
{
|
||||
|
275
src/request_body_processor/json.cc
Normal file
275
src/request_body_processor/json.cc
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* ModSecurity, http://www.modsecurity.org/
|
||||
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "request_body_processor/json.h"
|
||||
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace modsecurity {
|
||||
namespace RequestBodyProcessor {
|
||||
|
||||
/**
|
||||
* yajl callback functions
|
||||
* For more information on the function signatures and order, check
|
||||
* http://lloyd.github.com/yajl/yajl-1.0.12/structyajl__callbacks.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback for hash key values; we use those to define the variable names
|
||||
* under ARGS. Whenever we reach a new key, we update the current key value.
|
||||
*/
|
||||
int JSON::yajl_map_key(void *ctx, const unsigned char *key, size_t length) {
|
||||
JSON *tthis = reinterpret_cast<JSON *>(ctx);
|
||||
std::string safe_key;
|
||||
|
||||
/**
|
||||
* yajl does not provide us with null-terminated strings, but
|
||||
* rather expects us to copy the data from the key up to the
|
||||
* length informed; we create a standalone null-termined copy
|
||||
* in safe_key
|
||||
*/
|
||||
safe_key.assign((const char *)key, length);
|
||||
|
||||
tthis->debug(9, "New JSON hash key '" + safe_key + "'");
|
||||
|
||||
/**
|
||||
* TODO: How do we free the previously string value stored here?
|
||||
*/
|
||||
tthis->m_data.current_key = safe_key;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for null values
|
||||
*
|
||||
*/
|
||||
int JSON::yajl_null(void *ctx) {
|
||||
JSON *tthis = reinterpret_cast<JSON *>(ctx);
|
||||
|
||||
return tthis->addArgument("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for boolean values
|
||||
*/
|
||||
int JSON::yajl_boolean(void *ctx, int value) {
|
||||
JSON *tthis = reinterpret_cast<JSON *>(ctx);
|
||||
|
||||
if (value) {
|
||||
return tthis->addArgument("true");
|
||||
}
|
||||
|
||||
return tthis->addArgument("false");
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for string values
|
||||
*/
|
||||
int JSON::yajl_string(void *ctx, const unsigned char *value, size_t length) {
|
||||
JSON *tthis = reinterpret_cast<JSON *>(ctx);
|
||||
std::string v = std::string((const char*)value, length);
|
||||
|
||||
return tthis->addArgument(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for numbers; YAJL can use separate callbacks for integers/longs and
|
||||
* float/double values, but since we are not interested in using the numeric
|
||||
* values here, we use a generic handler which uses numeric strings
|
||||
*/
|
||||
int JSON::yajl_number(void *ctx, const char *value, size_t length) {
|
||||
JSON *tthis = reinterpret_cast<JSON *>(ctx);
|
||||
std::string v = std::string((const char*)value, length);
|
||||
|
||||
return tthis->addArgument(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for a new hash, which indicates a new subtree, labeled as the
|
||||
* current argument name, is being created
|
||||
*/
|
||||
int JSON::yajl_start_map(void *ctx) {
|
||||
JSON *tthis = reinterpret_cast<JSON *>(ctx);
|
||||
|
||||
/**
|
||||
* If we do not have a current_key, this is a top-level hash, so we do not
|
||||
* need to do anything
|
||||
*/
|
||||
if (tthis->m_data.current_key.empty() == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are already inside a hash context, and append or create the
|
||||
* current key name accordingly
|
||||
*/
|
||||
if (tthis->m_data.prefix.empty() == false) {
|
||||
tthis->m_data.prefix.append("." + tthis->m_data.current_key);
|
||||
} else {
|
||||
tthis->m_data.prefix.assign(tthis->m_data.current_key);
|
||||
}
|
||||
|
||||
tthis->debug(9, "New JSON hash context (prefix '" + \
|
||||
tthis->m_data.prefix + "')");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for end hash, meaning the current subtree is being closed, and that
|
||||
* we should go back to the parent variable label
|
||||
*/
|
||||
int JSON::yajl_end_map(void *ctx) {
|
||||
JSON *tthis = reinterpret_cast<JSON *>(ctx);
|
||||
size_t sep_pos = std::string::npos;
|
||||
|
||||
/**
|
||||
* If we have no prefix, then this is the end of a top-level hash and
|
||||
* we don't do anything
|
||||
*/
|
||||
if (tthis->m_data.prefix.empty() == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current prefix might or not include a separator character; top-level
|
||||
* hash keys do not have separators in the variable name
|
||||
*/
|
||||
sep_pos = tthis->m_data.prefix.find(".");
|
||||
|
||||
if (sep_pos != std::string::npos) {
|
||||
std::string tmp = tthis->m_data.prefix;
|
||||
tthis->m_data.prefix.assign(tmp, 0, sep_pos);
|
||||
tthis->m_data.current_key.assign(tmp, sep_pos + 1,
|
||||
tmp.length() - sep_pos - 1);
|
||||
} else {
|
||||
tthis->m_data.current_key.assign(tthis->m_data.prefix);
|
||||
tthis->m_data.prefix = "";
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int JSON::addArgument(const std::string& value) {
|
||||
/**
|
||||
* If we do not have a prefix, we cannot create a variable name
|
||||
* to reference this argument; for now we simply ignore these
|
||||
*/
|
||||
if (m_data.current_key.empty()) {
|
||||
debug(3, "Cannot add scalar value without an associated key");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (m_data.prefix.empty()) {
|
||||
m_transaction->addArgument("JSON", m_data.current_key, value);
|
||||
} else {
|
||||
m_transaction->addArgument("JSON", m_data.prefix + "." + \
|
||||
m_data.current_key, value);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
bool JSON::init() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool JSON::processChunk(const char *buf, unsigned int size, std::string *err) {
|
||||
/* Feed our parser and catch any errors */
|
||||
m_data.status = yajl_parse(m_data.handle,
|
||||
(const unsigned char *)buf, size);
|
||||
if (m_data.status != yajl_status_ok) {
|
||||
const unsigned char *e = yajl_get_error(m_data.handle, 0,
|
||||
(const unsigned char *)buf, size);
|
||||
/* We need to free the yajl error message later, how to do this? */
|
||||
err->assign((const char *)e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool JSON::complete(std::string *err) {
|
||||
/* Wrap up the parsing process */
|
||||
m_data.status = yajl_complete_parse(m_data.handle);
|
||||
if (m_data.status != yajl_status_ok) {
|
||||
const unsigned char *e = yajl_get_error(m_data.handle, 0, NULL, 0);
|
||||
/* We need to free the yajl error message later, how to do this? */
|
||||
err->assign((const char *)e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
JSON::JSON(Transaction *transaction) : m_transaction(transaction) {
|
||||
/**
|
||||
* yajl configuration and callbacks
|
||||
*/
|
||||
static yajl_callbacks callbacks = {
|
||||
yajl_null,
|
||||
yajl_boolean,
|
||||
NULL /* yajl_integer */,
|
||||
NULL /* yajl_double */,
|
||||
yajl_number,
|
||||
yajl_string,
|
||||
yajl_start_map,
|
||||
yajl_map_key,
|
||||
yajl_end_map,
|
||||
NULL /* yajl_start_array */,
|
||||
NULL /* yajl_end_array */
|
||||
};
|
||||
|
||||
|
||||
debug(4, "JSON parser initialization");
|
||||
|
||||
/**
|
||||
* Prefix and current key are initially empty
|
||||
*/
|
||||
m_data.prefix = "";
|
||||
m_data.current_key = "";
|
||||
|
||||
/**
|
||||
* yajl initialization
|
||||
*
|
||||
* yajl_parser_config definition:
|
||||
* http://lloyd.github.io/yajl/yajl-2.0.1/yajl__parse_8h.html#aec816c5518264d2ac41c05469a0f986c
|
||||
*
|
||||
* TODO: make UTF8 validation optional, as it depends on Content-Encoding
|
||||
*/
|
||||
debug(9, "yajl JSON parsing callback initialization");
|
||||
m_data.handle = yajl_alloc(&callbacks, NULL, this);
|
||||
|
||||
yajl_config(m_data.handle, yajl_allow_partial_values, 0);
|
||||
}
|
||||
|
||||
|
||||
JSON::~JSON() {
|
||||
debug(4, "JSON: Cleaning up JSON results");
|
||||
yajl_free(m_data.handle);
|
||||
}
|
||||
|
||||
|
||||
} // namespace RequestBodyProcessor
|
||||
} // namespace modsecurity
|
84
src/request_body_processor/json.h
Normal file
84
src/request_body_processor/json.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* ModSecurity, http://www.modsecurity.org/
|
||||
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <yajl/yajl_parse.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "modsecurity/transaction.h"
|
||||
#include "modsecurity/rules.h"
|
||||
|
||||
#ifndef SRC_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
#define SRC_REQUEST_BODY_PROCESSOR_JSON_H_
|
||||
|
||||
|
||||
namespace modsecurity {
|
||||
namespace RequestBodyProcessor {
|
||||
|
||||
|
||||
struct json_data {
|
||||
/* yajl configuration and parser state */
|
||||
yajl_handle handle;
|
||||
yajl_status status;
|
||||
|
||||
/* prefix is used to create data hierarchy (i.e., 'parent.child.value') */
|
||||
std::string prefix;
|
||||
std::string current_key;
|
||||
};
|
||||
|
||||
typedef struct json_data json_data;
|
||||
|
||||
|
||||
class JSON {
|
||||
public:
|
||||
explicit JSON(Transaction *transaction);
|
||||
~JSON();
|
||||
|
||||
bool init();
|
||||
bool processChunk(const char *buf, unsigned int size, std::string *err);
|
||||
bool complete(std::string *err);
|
||||
|
||||
int addArgument(const std::string& value);
|
||||
|
||||
static int yajl_end_map(void *ctx);
|
||||
static int yajl_start_map(void *ctx);
|
||||
static int yajl_number(void *ctx, const char *value, size_t length);
|
||||
static int yajl_string(void *ctx, const unsigned char *value,
|
||||
size_t length);
|
||||
static int yajl_boolean(void *ctx, int value);
|
||||
static int yajl_null(void *ctx);
|
||||
static int yajl_map_key(void *ctx, const unsigned char *key,
|
||||
size_t length);
|
||||
|
||||
#ifndef NO_LOGS
|
||||
void debug(int a, std::string str) {
|
||||
m_transaction->debug(a, str);
|
||||
}
|
||||
#endif
|
||||
json_data m_data;
|
||||
|
||||
private:
|
||||
Transaction *m_transaction;
|
||||
std::string m_header;
|
||||
};
|
||||
|
||||
|
||||
} // namespace RequestBodyProcessor
|
||||
} // namespace modsecurity
|
||||
|
||||
|
||||
#endif // SRC_REQUEST_BODY_PROCESSOR_JSON_H_
|
@ -38,6 +38,7 @@
|
||||
#include "modsecurity/modsecurity.h"
|
||||
#include "request_body_processor/multipart.h"
|
||||
#include "request_body_processor/xml.h"
|
||||
#include "request_body_processor/json.h"
|
||||
#include "audit_log/audit_log.h"
|
||||
#include "src/unique_id.h"
|
||||
#include "src/utils.h"
|
||||
@ -118,6 +119,7 @@ Transaction::Transaction(ModSecurity *ms, Rules *rules, void *logCbData)
|
||||
m_collections(ms->m_global_collection, ms->m_ip_collection,
|
||||
ms->m_session_collection, ms->m_user_collection,
|
||||
ms->m_resource_collection),
|
||||
m_json(new RequestBodyProcessor::JSON(this)),
|
||||
m_xml(new RequestBodyProcessor::XML(this)) {
|
||||
m_id = std::to_string(this->m_timeStamp) + \
|
||||
std::to_string(generate_transaction_unique_id());
|
||||
@ -163,6 +165,7 @@ Transaction::~Transaction() {
|
||||
|
||||
m_rules->decrementReferenceCount();
|
||||
|
||||
delete m_json;
|
||||
delete m_xml;
|
||||
}
|
||||
|
||||
@ -629,7 +632,6 @@ int Transaction::processRequestBody() {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
if (m_requestBodyProcessor == XMLRequestBody) {
|
||||
std::string error;
|
||||
if (m_xml->init() == true) {
|
||||
@ -649,6 +651,25 @@ int Transaction::processRequestBody() {
|
||||
m_collections.storeOrUpdateFirst("REQBODY_ERROR", "0");
|
||||
m_collections.storeOrUpdateFirst("REQBODY_PROCESSOR_ERROR", "0");
|
||||
}
|
||||
} else if (m_requestBodyProcessor == JSONRequestBody) {
|
||||
std::string error;
|
||||
if (m_json->init() == true) {
|
||||
m_json->processChunk(m_requestBody.str().c_str(),
|
||||
m_requestBody.str().size(),
|
||||
&error);
|
||||
m_json->complete(&error);
|
||||
}
|
||||
if (error.empty() == false) {
|
||||
m_collections.storeOrUpdateFirst("REQBODY_ERROR", "1");
|
||||
m_collections.storeOrUpdateFirst("REQBODY_PROCESSOR_ERROR", "1");
|
||||
m_collections.storeOrUpdateFirst("REQBODY_ERROR_MSG",
|
||||
"XML parsing error: " + error);
|
||||
m_collections.storeOrUpdateFirst("REQBODY_PROCESSOR_ERROR_MSG",
|
||||
"XML parsing error: " + error);
|
||||
} else {
|
||||
m_collections.storeOrUpdateFirst("REQBODY_ERROR", "0");
|
||||
m_collections.storeOrUpdateFirst("REQBODY_PROCESSOR_ERROR", "0");
|
||||
}
|
||||
} else if (m_requestBodyType == MultiPartRequestBody) {
|
||||
std::string error;
|
||||
std::string *a = m_collections.resolveFirst(
|
||||
|
84
test/test-cases/regression/request-body-parser-json.json
Normal file
84
test/test-cases/regression/request-body-parser-json.json
Normal file
@ -0,0 +1,84 @@
|
||||
[
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing JSON request body parser 1/1",
|
||||
"expected":{
|
||||
"debug_log": "Target value: \"bar\" \\(Variable: ARGS:foo\\)"
|
||||
},
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*",
|
||||
"Cookie": "PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"uri":"/?key=value&key=other_value",
|
||||
"method":"POST",
|
||||
"body": [
|
||||
"{",
|
||||
" \"foo\":\"bar\",",
|
||||
" \"mod\":\"sec\"",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecRequestBodyAccess On",
|
||||
"SecRule REQUEST_HEADERS:Content-Type \"application/json\" \"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON\"",
|
||||
"SecRule ARGS:foo \"bar\" \"id:'200441',phase:3,log\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled":1,
|
||||
"version_min":300000,
|
||||
"title":"Testing JSON request body parser 1/1",
|
||||
"expected":{
|
||||
"debug_log": "Target value: \"bar\" \\(Variable: ARGS:first_level.first_key\\)"
|
||||
},
|
||||
"client":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":123
|
||||
},
|
||||
"request":{
|
||||
"headers":{
|
||||
"Host":"localhost",
|
||||
"User-Agent":"curl/7.38.0",
|
||||
"Accept":"*/*",
|
||||
"Cookie": "PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"uri":"/?key=value&key=other_value",
|
||||
"method":"POST",
|
||||
"body": [
|
||||
"{",
|
||||
"\"first_level\":",
|
||||
"{",
|
||||
" \"first_key\":\"bar\",",
|
||||
" \"second_key\":\"sec\"",
|
||||
"}",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"server":{
|
||||
"ip":"200.249.12.31",
|
||||
"port":80
|
||||
},
|
||||
"rules":[
|
||||
"SecRuleEngine On",
|
||||
"SecRequestBodyAccess On",
|
||||
"SecRule REQUEST_HEADERS:Content-Type \"application/json\" \"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON\"",
|
||||
"SecRule ARGS \"bar\" \"id:'200441',phase:3,log\""
|
||||
]
|
||||
}
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user