mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 13:56:01 +03:00
Added support for JSON body processor
This commit is contained in:
parent
410aca9d78
commit
c23097ce18
@ -12,6 +12,7 @@ mod_security2_la_SOURCES = acmp.c \
|
|||||||
msc_crypt.c \
|
msc_crypt.c \
|
||||||
msc_geo.c \
|
msc_geo.c \
|
||||||
msc_gsb.c \
|
msc_gsb.c \
|
||||||
|
msc_json.c \
|
||||||
msc_logging.c \
|
msc_logging.c \
|
||||||
msc_lua.c \
|
msc_lua.c \
|
||||||
msc_multipart.c \
|
msc_multipart.c \
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "modsecurity.h"
|
#include "modsecurity.h"
|
||||||
#include "msc_parsers.h"
|
#include "msc_parsers.h"
|
||||||
#include "msc_util.h"
|
#include "msc_util.h"
|
||||||
|
#include "msc_json.h"
|
||||||
#include "msc_xml.h"
|
#include "msc_xml.h"
|
||||||
#include "apr_version.h"
|
#include "apr_version.h"
|
||||||
|
|
||||||
@ -255,6 +256,9 @@ static apr_status_t modsecurity_tx_cleanup(void *data) {
|
|||||||
/* XML processor cleanup. */
|
/* XML processor cleanup. */
|
||||||
if (msr->xml != NULL) xml_cleanup(msr);
|
if (msr->xml != NULL) xml_cleanup(msr);
|
||||||
|
|
||||||
|
/* JSON processor cleanup. */
|
||||||
|
if (msr->json != NULL) json_cleanup(msr);
|
||||||
|
|
||||||
// TODO: Why do we ignore return code here?
|
// TODO: Why do we ignore return code here?
|
||||||
modsecurity_request_body_clear(msr, &my_error_msg);
|
modsecurity_request_body_clear(msr, &my_error_msg);
|
||||||
if (my_error_msg != NULL) {
|
if (my_error_msg != NULL) {
|
||||||
|
@ -38,6 +38,7 @@ typedef struct msc_parm msc_parm;
|
|||||||
#include "msc_multipart.h"
|
#include "msc_multipart.h"
|
||||||
#include "msc_pcre.h"
|
#include "msc_pcre.h"
|
||||||
#include "msc_util.h"
|
#include "msc_util.h"
|
||||||
|
#include "msc_json.h"
|
||||||
#include "msc_xml.h"
|
#include "msc_xml.h"
|
||||||
#include "msc_geo.h"
|
#include "msc_geo.h"
|
||||||
#include "msc_gsb.h"
|
#include "msc_gsb.h"
|
||||||
@ -368,6 +369,7 @@ struct modsec_rec {
|
|||||||
multipart_data *mpd; /* MULTIPART processor data structure */
|
multipart_data *mpd; /* MULTIPART processor data structure */
|
||||||
|
|
||||||
xml_data *xml; /* XML processor data structure */
|
xml_data *xml; /* XML processor data structure */
|
||||||
|
json_data *json; /* JSON processor data structure */
|
||||||
|
|
||||||
/* audit logging */
|
/* audit logging */
|
||||||
char *new_auditlog_boundary;
|
char *new_auditlog_boundary;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
||||||
re re_operators re_actions re_tfns re_variables \
|
re re_operators re_actions re_tfns re_variables msc_json \
|
||||||
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
||||||
persist_dbm msc_reqbody pdf_protect msc_geo msc_gsb msc_crypt msc_tree msc_unicode acmp msc_lua
|
persist_dbm msc_reqbody pdf_protect msc_geo msc_gsb msc_crypt msc_tree msc_unicode acmp msc_lua
|
||||||
|
|
||||||
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
|
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h msc_json.h \
|
||||||
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
||||||
msc_geo.h msc_gsb.h msc_crypt.h msc_tree.h msc_unicode.h acmp.h utf8tables.h msc_lua.h
|
msc_geo.h msc_gsb.h msc_crypt.h msc_tree.h msc_unicode.h acmp.h utf8tables.h msc_lua.h
|
||||||
|
|
||||||
|
313
apache2/msc_json.c
Normal file
313
apache2/msc_json.c
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2004-2011 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 "msc_json.h"
|
||||||
|
|
||||||
|
int json_add_argument(modsec_rec *msr, const char *value, unsigned length)
|
||||||
|
{
|
||||||
|
msc_arg *arg = (msc_arg *) NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we do not have a prefix, we cannot create a variable name
|
||||||
|
* to reference this argument; for now we simply ignore these
|
||||||
|
*/
|
||||||
|
if (!msr->json->current_key) {
|
||||||
|
msr_log(msr, 3, "Cannot add scalar value without an associated key");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = (msc_arg *) apr_pcalloc(msr->mp, sizeof(msc_arg));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Argument name is 'prefix + current_key'
|
||||||
|
*/
|
||||||
|
if (msr->json->prefix) {
|
||||||
|
arg->name = apr_psprintf(msr->mp, "%s.%s", msr->json->prefix,
|
||||||
|
msr->json->current_key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arg->name = apr_psprintf(msr->mp, "%s", msr->json->current_key);
|
||||||
|
}
|
||||||
|
arg->name_len = strlen(arg->name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Argument value is copied from the provided string
|
||||||
|
*/
|
||||||
|
arg->value = apr_pstrmemdup(msr->mp, value, length);
|
||||||
|
arg->value_len = length;
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Adding JSON argument '%s' with value '%s'",
|
||||||
|
arg->name, arg->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_table_addn(msr->arguments,
|
||||||
|
log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *) arg);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static int yajl_map_key(void *ctx, const unsigned char *key, unsigned int length)
|
||||||
|
{
|
||||||
|
modsec_rec *msr = (modsec_rec *) ctx;
|
||||||
|
unsigned char *safe_key = (unsigned char *) NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = apr_pstrndup(msr->mp, key, length);
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "New JSON hash key '%s'", safe_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: How do we free the previously string value stored here?
|
||||||
|
*/
|
||||||
|
msr->json->current_key = safe_key;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for null values
|
||||||
|
*
|
||||||
|
* TODO: Is there a way to define true null parameter values instead of
|
||||||
|
* empty values?
|
||||||
|
*/
|
||||||
|
static int yajl_null(void *ctx)
|
||||||
|
{
|
||||||
|
modsec_rec *msr = (modsec_rec *) ctx;
|
||||||
|
|
||||||
|
return json_add_argument(msr, "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for boolean values
|
||||||
|
*/
|
||||||
|
static int yajl_boolean(void *ctx, int value)
|
||||||
|
{
|
||||||
|
modsec_rec *msr = (modsec_rec *) ctx;
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
return json_add_argument(msr, "true", strlen("true"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return json_add_argument(msr, "false", strlen("false"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for string values
|
||||||
|
*/
|
||||||
|
static int yajl_string(void *ctx, const unsigned char *value, unsigned int length)
|
||||||
|
{
|
||||||
|
modsec_rec *msr = (modsec_rec *) ctx;
|
||||||
|
|
||||||
|
return json_add_argument(msr, value, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
static int yajl_number(void *ctx, const unsigned char *value, unsigned int length)
|
||||||
|
{
|
||||||
|
modsec_rec *msr = (modsec_rec *) ctx;
|
||||||
|
|
||||||
|
return json_add_argument(msr, value, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for a new hash, which indicates a new subtree, labeled as the current
|
||||||
|
* argument name, is being created
|
||||||
|
*/
|
||||||
|
static int yajl_start_map(void *ctx)
|
||||||
|
{
|
||||||
|
modsec_rec *msr = (modsec_rec *) ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we do not have a current_key, this is a top-level hash, so we do not
|
||||||
|
* need to do anything
|
||||||
|
*/
|
||||||
|
if (!msr->json->current_key) return 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we are already inside a hash context, and append or create the
|
||||||
|
* current key name accordingly
|
||||||
|
*/
|
||||||
|
if (msr->json->prefix) {
|
||||||
|
msr->json->prefix = apr_psprintf(msr->mp, "%s.%s", msr->json->prefix,
|
||||||
|
msr->json->current_key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
msr->json->prefix = apr_pstrdup(msr->mp, msr->json->current_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "New JSON hash context (prefix '%s')", msr->json->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
|
||||||
|
*/
|
||||||
|
static int yajl_end_map(void *ctx)
|
||||||
|
{
|
||||||
|
modsec_rec *msr = (modsec_rec *) ctx;
|
||||||
|
unsigned char *separator = (unsigned char *) NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we have no prefix, then this is the end of a top-level hash and
|
||||||
|
* we don't do anything
|
||||||
|
*/
|
||||||
|
if (msr->json->prefix == NULL) return 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current prefix might or not include a separator character; top-level
|
||||||
|
* hash keys do not have separators in the variable name
|
||||||
|
*/
|
||||||
|
separator = strrchr(msr->json->prefix, '.');
|
||||||
|
|
||||||
|
if (separator) {
|
||||||
|
msr->json->prefix = apr_pstrmemdup(msr->mp, msr->json->prefix,
|
||||||
|
separator - msr->json->prefix);
|
||||||
|
msr->json->current_key = apr_psprintf(msr->mp, "%s", separator + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/**
|
||||||
|
* TODO: Check if it is safe to do this kind of pointer tricks
|
||||||
|
*/
|
||||||
|
msr->json->current_key = msr->json->prefix;
|
||||||
|
msr->json->prefix = (unsigned char *) NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise JSON parser.
|
||||||
|
*/
|
||||||
|
int json_init(modsec_rec *msr, char **error_msg) {
|
||||||
|
/**
|
||||||
|
* yajl configuration and callbacks
|
||||||
|
*/
|
||||||
|
static yajl_parser_config config = { 0, 1 };
|
||||||
|
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 */
|
||||||
|
};
|
||||||
|
|
||||||
|
if (error_msg == NULL) return -1;
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
|
msr_log(msr, 4, "JSON parser initialization");
|
||||||
|
msr->json = apr_pcalloc(msr->mp, sizeof(json_data));
|
||||||
|
if (msr->json == NULL) return -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefix and current key are initially empty
|
||||||
|
*/
|
||||||
|
msr->json->prefix = (unsigned char *) NULL;
|
||||||
|
msr->json->current_key = (unsigned char *) NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* yajl initialization
|
||||||
|
*
|
||||||
|
* yajl_parser_config definition:
|
||||||
|
* http://lloyd.github.com/yajl/yajl-1.0.12/structyajl__parser__config.html
|
||||||
|
*
|
||||||
|
* TODO: make UTF8 validation optional, as it depends on Content-Encoding
|
||||||
|
*/
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "yajl JSON parsing callback initialization");
|
||||||
|
}
|
||||||
|
msr->json->handle = yajl_alloc(&callbacks, &config, NULL, msr);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed one chunk of data to the JSON parser.
|
||||||
|
*/
|
||||||
|
int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) {
|
||||||
|
if (error_msg == NULL) return -1;
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
|
/* Feed our parser and catch any errors */
|
||||||
|
msr->json->status = yajl_parse(msr->json->handle, buf, size);
|
||||||
|
if (msr->json->status != yajl_status_ok &&
|
||||||
|
msr->json->status != yajl_status_insufficient_data) {
|
||||||
|
/* We need to free the yajl error message later, how to do this? */
|
||||||
|
*error_msg = yajl_get_error(msr->json->handle, 0, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalise JSON parsing.
|
||||||
|
*/
|
||||||
|
int json_complete(modsec_rec *msr, char **error_msg) {
|
||||||
|
char *json_data = (char *) NULL;
|
||||||
|
|
||||||
|
if (error_msg == NULL) return -1;
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
|
/* Wrap up the parsing process */
|
||||||
|
msr->json->status = yajl_parse_complete(msr->json->handle);
|
||||||
|
if (msr->json->status != yajl_status_ok &&
|
||||||
|
msr->json->status != yajl_status_insufficient_data) {
|
||||||
|
/* We need to free the yajl error message later, how to do this? */
|
||||||
|
*error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the resources used for XML parsing.
|
||||||
|
*/
|
||||||
|
apr_status_t json_cleanup(modsec_rec *msr) {
|
||||||
|
msr_log(msr, 4, "JSON: Cleaning up JSON results");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
48
apache2/msc_json.h
Normal file
48
apache2/msc_json.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2004-2011 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MSC_JSON_H_
|
||||||
|
#define _MSC_JSON_H_
|
||||||
|
|
||||||
|
typedef struct json_data json_data;
|
||||||
|
|
||||||
|
#include "modsecurity.h"
|
||||||
|
#include <yajl/yajl_parse.h>
|
||||||
|
|
||||||
|
/* Structures */
|
||||||
|
struct json_data {
|
||||||
|
/* yajl configuration and parser state */
|
||||||
|
yajl_handle handle;
|
||||||
|
yajl_status status;
|
||||||
|
|
||||||
|
/* error reporting and JSON array flag */
|
||||||
|
unsigned char *yajl_error;
|
||||||
|
|
||||||
|
/* prefix is used to create data hierarchy (i.e., 'parent.child.value') */
|
||||||
|
unsigned char *prefix;
|
||||||
|
unsigned char *current_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Functions */
|
||||||
|
|
||||||
|
int DSOLOCAL json_init(modsec_rec *msr, char **error_msg);
|
||||||
|
|
||||||
|
int DSOLOCAL json_process(modsec_rec *msr, const char *buf,
|
||||||
|
unsigned int size, char **error_msg);
|
||||||
|
|
||||||
|
int DSOLOCAL json_complete(modsec_rec *msr, char **error_msg);
|
||||||
|
|
||||||
|
apr_status_t DSOLOCAL json_cleanup(modsec_rec *msr);
|
||||||
|
|
||||||
|
#endif
|
@ -127,6 +127,14 @@ apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) {
|
|||||||
msr_log(msr, 2, "%s", *error_msg);
|
msr_log(msr, 2, "%s", *error_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
||||||
|
if (json_init(msr, &my_error_msg) < 0) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "JSON parsing error (init): %s", my_error_msg);
|
||||||
|
msr->msc_reqbody_error = 1;
|
||||||
|
msr->msc_reqbody_error_msg = my_error_msg;
|
||||||
|
msr_log(msr, 2, "%s", *error_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||||
/* Do nothing, URLENCODED processor does not support streaming yet. */
|
/* Do nothing, URLENCODED processor does not support streaming yet. */
|
||||||
}
|
}
|
||||||
@ -344,6 +352,18 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
|||||||
msr_log(msr, 2, "%s", *error_msg);
|
msr_log(msr, 2, "%s", *error_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
||||||
|
/* Increase per-request data length counter. */
|
||||||
|
msr->msc_reqbody_no_files_length += length;
|
||||||
|
|
||||||
|
/* Process data as XML. */
|
||||||
|
if (json_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "JSON parsing error: %s", my_error_msg);
|
||||||
|
msr->msc_reqbody_error = 1;
|
||||||
|
msr->msc_reqbody_error_msg = *error_msg;
|
||||||
|
msr_log(msr, 2, "%s", *error_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||||
/* Increase per-request data length counter. */
|
/* Increase per-request data length counter. */
|
||||||
msr->msc_reqbody_no_files_length += length;
|
msr->msc_reqbody_no_files_length += length;
|
||||||
@ -601,6 +621,15 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
||||||
|
if (json_complete(msr, &my_error_msg) < 0) {
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "JSON parser error: %s", my_error_msg);
|
||||||
|
msr->msc_reqbody_error = 1;
|
||||||
|
msr->msc_reqbody_error_msg = *error_msg;
|
||||||
|
msr_log(msr, 2, "%s", *error_msg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||||
return modsecurity_request_body_end_urlencoded(msr, error_msg);
|
return modsecurity_request_body_end_urlencoded(msr, error_msg);
|
||||||
}
|
}
|
||||||
|
@ -698,6 +698,9 @@ if test "$build_mlogc" -ne 0; then
|
|||||||
CHECK_CURL()
|
CHECK_CURL()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check for YAJL libs (for JSON body processor)
|
||||||
|
AC_SEARCH_LIBS([yajl_alloc], [yajl])
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile])
|
AC_CONFIG_FILES([Makefile])
|
||||||
AC_CONFIG_FILES([tools/Makefile])
|
AC_CONFIG_FILES([tools/Makefile])
|
||||||
if test "$build_alp2" -ne 0; then
|
if test "$build_alp2" -ne 0; then
|
||||||
|
@ -23,6 +23,12 @@ SecRequestBodyAccess On
|
|||||||
SecRule REQUEST_HEADERS:Content-Type "text/xml" \
|
SecRule REQUEST_HEADERS:Content-Type "text/xml" \
|
||||||
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
|
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
|
||||||
|
|
||||||
|
# Enable JSON request body parser.
|
||||||
|
# Initiate JSON Processor in case of JSON content-type; change accordingly
|
||||||
|
# if your application does not use 'application/json'
|
||||||
|
#
|
||||||
|
SecRule REQUEST_HEADERS:Content-Type "application/json" \
|
||||||
|
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
|
||||||
|
|
||||||
# Maximum request body size we will accept for buffering. If you support
|
# Maximum request body size we will accept for buffering. If you support
|
||||||
# file uploads then the value given on the first line has to be as large
|
# file uploads then the value given on the first line has to be as large
|
||||||
@ -52,7 +58,7 @@ SecRequestBodyLimitAction Reject
|
|||||||
# or log a high-severity alert (when deployed in detection-only mode).
|
# or log a high-severity alert (when deployed in detection-only mode).
|
||||||
#
|
#
|
||||||
SecRule REQBODY_ERROR "!@eq 0" \
|
SecRule REQBODY_ERROR "!@eq 0" \
|
||||||
"id:'200001', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
|
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
|
||||||
|
|
||||||
# By default be strict with what we accept in the multipart/form-data
|
# By default be strict with what we accept in the multipart/form-data
|
||||||
# request body. If the rule below proves to be too strict for your
|
# request body. If the rule below proves to be too strict for your
|
||||||
@ -60,7 +66,7 @@ SecRule REQBODY_ERROR "!@eq 0" \
|
|||||||
# _not_ to remove it altogether.
|
# _not_ to remove it altogether.
|
||||||
#
|
#
|
||||||
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
|
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
|
||||||
"id:'200002',phase:2,t:none,log,deny,status:400, \
|
"id:'200003',phase:2,t:none,log,deny,status:400, \
|
||||||
msg:'Multipart request body failed strict validation: \
|
msg:'Multipart request body failed strict validation: \
|
||||||
PE %{REQBODY_PROCESSOR_ERROR}, \
|
PE %{REQBODY_PROCESSOR_ERROR}, \
|
||||||
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
|
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
|
||||||
@ -78,7 +84,7 @@ FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
|
|||||||
# Did we see anything that might be a boundary?
|
# Did we see anything that might be a boundary?
|
||||||
#
|
#
|
||||||
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
|
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
|
||||||
"id:'200003',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
|
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
|
||||||
|
|
||||||
# PCRE Tuning
|
# PCRE Tuning
|
||||||
# We want to avoid a potential RegEx DoS condition
|
# We want to avoid a potential RegEx DoS condition
|
||||||
@ -92,7 +98,7 @@ SecPcreMatchLimitRecursion 1000
|
|||||||
# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
|
# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
|
||||||
#
|
#
|
||||||
SecRule TX:/^MSC_/ "!@streq 0" \
|
SecRule TX:/^MSC_/ "!@streq 0" \
|
||||||
"id:'200004',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
|
"id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
|
||||||
|
|
||||||
|
|
||||||
# -- Response body handling --------------------------------------------------
|
# -- Response body handling --------------------------------------------------
|
||||||
@ -211,4 +217,12 @@ SecCookieFormat 0
|
|||||||
# these directives helps to reduce false positives and negatives.
|
# these directives helps to reduce false positives and negatives.
|
||||||
#
|
#
|
||||||
#SecUnicodeCodePage 20127
|
#SecUnicodeCodePage 20127
|
||||||
#SecUnicodeMapFile unicode.mapping
|
#SecUnicodeMapFile unicode.mappinga
|
||||||
|
|
||||||
|
# Improve the quality of ModSecurity by sharing information about your
|
||||||
|
# current ModSecurity version and dependencies versions.
|
||||||
|
# The following information will be shared: ModSecurity version,
|
||||||
|
# Web Server version, APR version, PCRE version, Lua version, Libxml2
|
||||||
|
# version, Anonymous unique id for host.
|
||||||
|
SecStatusEngine On
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user