mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
MODSEC-104
This commit is contained in:
@@ -58,6 +58,7 @@ void *create_directory_config(apr_pool_t *mp, char *path)
|
||||
dcfg->debuglog_fd = NOT_SET_P;
|
||||
|
||||
dcfg->of_limit = NOT_SET;
|
||||
dcfg->if_limit_action = NOT_SET;
|
||||
dcfg->of_limit_action = NOT_SET;
|
||||
dcfg->of_mime_types = NOT_SET_P;
|
||||
dcfg->of_mime_types_cleared = NOT_SET;
|
||||
@@ -253,6 +254,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
|
||||
|
||||
merged->of_limit = (child->of_limit == NOT_SET
|
||||
? parent->of_limit : child->of_limit);
|
||||
merged->if_limit_action = (child->if_limit_action == NOT_SET
|
||||
? parent->if_limit_action : child->if_limit_action);
|
||||
merged->of_limit_action = (child->of_limit_action == NOT_SET
|
||||
? parent->of_limit_action : child->of_limit_action);
|
||||
merged->reqintercept_oe = (child->reqintercept_oe == NOT_SET
|
||||
@@ -492,6 +495,7 @@ void init_directory_config(directory_config *dcfg)
|
||||
if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT;
|
||||
if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0;
|
||||
if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT;
|
||||
if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
|
||||
if (dcfg->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
|
||||
|
||||
if (dcfg->of_mime_types == NOT_SET_P) {
|
||||
@@ -1469,6 +1473,11 @@ static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg,
|
||||
directory_config *dcfg = (directory_config *)_dcfg;
|
||||
if (dcfg == NULL) return NULL;
|
||||
|
||||
if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
|
||||
dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
|
||||
else
|
||||
if (strcasecmp(p1, "Reject") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
|
||||
@@ -1478,6 +1487,26 @@ static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg,
|
||||
const char *p1)
|
||||
{
|
||||
directory_config *dcfg = (directory_config *)_dcfg;
|
||||
if (dcfg == NULL) return NULL;
|
||||
|
||||
if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
|
||||
dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcasecmp(p1, "On") == 0) dcfg->if_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
|
||||
else
|
||||
if (strcasecmp(p1, "Off") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
|
||||
else
|
||||
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyProcessPartial: %s", p1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg,
|
||||
const char *_p1)
|
||||
{
|
||||
@@ -1526,8 +1555,10 @@ static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
|
||||
else
|
||||
if (strcasecmp(p1, "off") == 0) dcfg->is_enabled = MODSEC_DISABLED;
|
||||
else
|
||||
if (strcasecmp(p1, "detectiononly") == 0) dcfg->is_enabled = MODSEC_DETECTION_ONLY;
|
||||
else
|
||||
if (strcasecmp(p1, "detectiononly") == 0) {
|
||||
dcfg->is_enabled = MODSEC_DETECTION_ONLY;
|
||||
dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
|
||||
} else
|
||||
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1);
|
||||
|
||||
return NULL;
|
||||
@@ -2158,6 +2189,14 @@ const command_rec module_directives[] = {
|
||||
"what happens when the response body limit is reached"
|
||||
),
|
||||
|
||||
AP_INIT_TAKE1 (
|
||||
"SecRequestBodyProcessPartial",
|
||||
cmd_resquest_body_limit_action,
|
||||
NULL,
|
||||
CMD_SCOPE_ANY,
|
||||
"what happens when the request body limit is reached"
|
||||
),
|
||||
|
||||
AP_INIT_ITERATE (
|
||||
"SecResponseBodyMimeType",
|
||||
cmd_response_body_mime_type,
|
||||
|
@@ -391,6 +391,7 @@ static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
|
||||
if (len > msr->txcfg->of_limit) {
|
||||
msr_log(msr, 1, "Output filter: Content-Length (%s) over the limit (%ld).",
|
||||
log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit);
|
||||
msr->outbound_error = 1;
|
||||
return -2; /* Over the limit. */
|
||||
}
|
||||
}
|
||||
@@ -555,6 +556,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
||||
}
|
||||
}
|
||||
|
||||
msr->outbound_error = 0;
|
||||
/* Decide whether to observe the response body. */
|
||||
rc = output_filter_init(msr, f, bb_in);
|
||||
switch(rc) {
|
||||
@@ -657,6 +659,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
||||
* ready to accept. We need to decide what we want to do
|
||||
* about it.
|
||||
*/
|
||||
msr->outbound_error = 1;
|
||||
if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT) {
|
||||
/* Reject response. */
|
||||
msr_log(msr, 1, "Output filter: Response body too large (over limit of %ld, "
|
||||
|
@@ -726,11 +726,15 @@ static int hook_request_late(request_rec *r) {
|
||||
/* Check that the request body is not too long, but only
|
||||
* if configuration allows for request body access.
|
||||
*/
|
||||
msr->inbound_error = 0;
|
||||
if (msr->txcfg->reqbody_access == 1) {
|
||||
/* Check request body limit (non-chunked requests only). */
|
||||
if (msr->request_content_length > msr->txcfg->reqbody_limit) {
|
||||
msr_log(msr, 1, "Request body (Content-Length) is larger than the "
|
||||
"configured limit (%ld).", msr->txcfg->reqbody_limit);
|
||||
msr->inbound_error = 1;
|
||||
|
||||
if(msr->txcfg->if_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT)
|
||||
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
}
|
||||
}
|
||||
@@ -763,8 +767,11 @@ static int hook_request_late(request_rec *r) {
|
||||
if (my_error_msg != NULL) {
|
||||
msr_log(msr, 1, "%s", my_error_msg);
|
||||
}
|
||||
msr->inbound_error = 1;
|
||||
if(msr->txcfg->if_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT) {
|
||||
r->connection->keepalive = AP_CONN_CLOSE;
|
||||
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
/* allow through */
|
||||
|
@@ -94,6 +94,9 @@ typedef struct msc_string msc_string;
|
||||
#define REQUEST_BODY_FORCEBUF_OFF 0
|
||||
#define REQUEST_BODY_FORCEBUF_ON 1
|
||||
|
||||
#define REQUEST_BODY_LIMIT_ACTION_REJECT 0
|
||||
#define REQUEST_BODY_LIMIT_ACTION_PARTIAL 1
|
||||
|
||||
#define SECACTION_TARGETS "REMOTE_ADDR"
|
||||
#define SECACTION_ARGS "@unconditionalMatch"
|
||||
|
||||
@@ -266,6 +269,8 @@ struct modsec_rec {
|
||||
apr_table_t *request_cookies;
|
||||
|
||||
unsigned int urlencoded_error;
|
||||
unsigned int inbound_error;
|
||||
unsigned int outbound_error;
|
||||
|
||||
unsigned int is_relevant;
|
||||
|
||||
@@ -395,6 +400,7 @@ struct directory_config {
|
||||
apr_table_t *of_mime_types;
|
||||
int of_mime_types_cleared;
|
||||
int of_limit_action;
|
||||
int if_limit_action;
|
||||
|
||||
const char *debuglog_name;
|
||||
int debuglog_level;
|
||||
|
@@ -1453,6 +1453,30 @@ static int var_urlencoded_error_generate(modsec_rec *msr, msre_var *var, msre_ru
|
||||
}
|
||||
}
|
||||
|
||||
/* INBOUND_DATA_ERROR */
|
||||
|
||||
static int var_inbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
||||
apr_table_t *vartab, apr_pool_t *mptmp)
|
||||
{
|
||||
if (msr->inbound_error) {
|
||||
return var_simple_generate(var, vartab, mptmp, "1");
|
||||
} else {
|
||||
return var_simple_generate(var, vartab, mptmp, "0");
|
||||
}
|
||||
}
|
||||
|
||||
/* OUTBOUND_DATA_ERROR */
|
||||
|
||||
static int var_outbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
|
||||
apr_table_t *vartab, apr_pool_t *mptmp)
|
||||
{
|
||||
if (msr->outbound_error) {
|
||||
return var_simple_generate(var, vartab, mptmp, "1");
|
||||
} else {
|
||||
return var_simple_generate(var, vartab, mptmp, "0");
|
||||
}
|
||||
}
|
||||
|
||||
apr_time_t calculate_perf_combined(modsec_rec *msr) {
|
||||
return msr->time_phase1 + msr->time_phase2 + msr->time_phase3 + msr->time_phase4
|
||||
+ msr->time_phase5 + msr->time_storage_write /* time_storage_read is already
|
||||
@@ -3208,6 +3232,28 @@ void msre_engine_register_default_variables(msre_engine *engine) {
|
||||
PHASE_REQUEST_HEADERS
|
||||
);
|
||||
|
||||
/* INBOUND_DATA_ERROR */
|
||||
msre_engine_variable_register(engine,
|
||||
"INBOUND_DATA_ERROR",
|
||||
VAR_SIMPLE,
|
||||
0, 0,
|
||||
NULL,
|
||||
var_inbound_error_generate,
|
||||
VAR_DONT_CACHE, /* flag */
|
||||
PHASE_REQUEST_BODY
|
||||
);
|
||||
|
||||
/* OUTBOUND_DATA_ERROR */
|
||||
msre_engine_variable_register(engine,
|
||||
"OUTBOUND_DATA_ERROR",
|
||||
VAR_SIMPLE,
|
||||
0, 0,
|
||||
NULL,
|
||||
var_outbound_error_generate,
|
||||
VAR_DONT_CACHE, /* flag */
|
||||
PHASE_RESPONSE_BODY
|
||||
);
|
||||
|
||||
/* USER */
|
||||
msre_engine_variable_register(engine,
|
||||
"USER",
|
||||
|
Reference in New Issue
Block a user