mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 13:56:01 +03:00
Added experiemental support for content injection.
This commit is contained in:
parent
20c0b11dd9
commit
e0a8602929
6
CHANGES
6
CHANGES
@ -2,6 +2,12 @@
|
|||||||
?? ??? 2007 - 2.2.0-trunk
|
?? ??? 2007 - 2.2.0-trunk
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
* Added experimental support for content injection. Directive SecContentInjection
|
||||||
|
(On|Off) controls whether injection is taking place. Actions "prepend"
|
||||||
|
and "append" inject content when executed. Do note that it is your
|
||||||
|
responsibility to make sure the response is of the appropriate
|
||||||
|
content type (e.g. HTML, plain text, etc).
|
||||||
|
|
||||||
* Added string comparison operators with support for macro expansion:
|
* Added string comparison operators with support for macro expansion:
|
||||||
@contains, @is, @beginsWith and @endsWith.
|
@contains, @is, @beginsWith and @endsWith.
|
||||||
|
|
||||||
|
@ -81,6 +81,9 @@ void *create_directory_config(apr_pool_t *mp, char *path) {
|
|||||||
dcfg->data_dir = NOT_SET_P;
|
dcfg->data_dir = NOT_SET_P;
|
||||||
dcfg->webappid = NOT_SET_P;
|
dcfg->webappid = NOT_SET_P;
|
||||||
|
|
||||||
|
/* Content injection. */
|
||||||
|
dcfg->content_injection_enabled = NOT_SET;
|
||||||
|
|
||||||
return dcfg;
|
return dcfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,6 +359,10 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) {
|
|||||||
merged->webappid = (child->webappid == NOT_SET_P
|
merged->webappid = (child->webappid == NOT_SET_P
|
||||||
? parent->webappid : child->webappid);
|
? parent->webappid : child->webappid);
|
||||||
|
|
||||||
|
/* Content injection. */
|
||||||
|
merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET
|
||||||
|
? parent->content_injection_enabled : child->content_injection_enabled);
|
||||||
|
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,6 +421,9 @@ void init_directory_config(directory_config *dcfg) {
|
|||||||
/* Misc */
|
/* Misc */
|
||||||
if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
|
if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
|
||||||
if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
|
if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
|
||||||
|
|
||||||
|
/* Content injection. */
|
||||||
|
if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -696,6 +706,13 @@ static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag) {
|
||||||
|
directory_config *dcfg = (directory_config *)_dcfg;
|
||||||
|
if (dcfg == NULL) return NULL;
|
||||||
|
dcfg->content_injection_enabled = flag;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1) {
|
static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1) {
|
||||||
directory_config *dcfg = (directory_config *)_dcfg;
|
directory_config *dcfg = (directory_config *)_dcfg;
|
||||||
|
|
||||||
@ -1175,6 +1192,14 @@ const command_rec module_directives[] = {
|
|||||||
"Path of the directory to which server will be chrooted"
|
"Path of the directory to which server will be chrooted"
|
||||||
),
|
),
|
||||||
|
|
||||||
|
AP_INIT_FLAG (
|
||||||
|
"SecContentInjection",
|
||||||
|
cmd_content_injection,
|
||||||
|
NULL,
|
||||||
|
CMD_SCOPE_ANY,
|
||||||
|
"On or Off"
|
||||||
|
),
|
||||||
|
|
||||||
AP_INIT_TAKE1 (
|
AP_INIT_TAKE1 (
|
||||||
"SecCookieFormat",
|
"SecCookieFormat",
|
||||||
cmd_cookie_format,
|
cmd_cookie_format,
|
||||||
|
@ -384,7 +384,7 @@ static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
|
|||||||
apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
||||||
request_rec *r = f->r;
|
request_rec *r = f->r;
|
||||||
modsec_rec *msr = (modsec_rec *)f->ctx;
|
modsec_rec *msr = (modsec_rec *)f->ctx;
|
||||||
apr_bucket *bucket;
|
apr_bucket *bucket = NULL, *eos_bucket = NULL;
|
||||||
apr_status_t rc;
|
apr_status_t rc;
|
||||||
|
|
||||||
if (msr == NULL) {
|
if (msr == NULL) {
|
||||||
@ -445,6 +445,40 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
/* Continue (observe the response body). */
|
/* Continue (observe the response body). */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If injecting content unset headers now.
|
||||||
|
if (msr->txcfg->content_injection_enabled == 0) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Content Injection: Not enabled.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((msr->content_prepend) || (msr->content_append)) {
|
||||||
|
apr_table_unset(msr->r->headers_out, "Content-Length");
|
||||||
|
apr_table_unset(msr->r->headers_out, "Last-Modified");
|
||||||
|
apr_table_unset(msr->r->headers_out, "ETag");
|
||||||
|
apr_table_unset(msr->r->headers_out, "Expires");
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Content Injection: Removing headers (C-L, L-M, Etag, Expires).");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Content Injection: Nothing to inject.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content injection (prepend & non-buffering).
|
||||||
|
if (msr->txcfg->content_injection_enabled && msr->content_prepend) {
|
||||||
|
apr_bucket *bucket_ci = apr_bucket_heap_create(msr->content_prepend,
|
||||||
|
msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
|
||||||
|
APR_BRIGADE_INSERT_HEAD(bb_in, bucket_ci);
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Content Injection (nb): Added content to top: %s",
|
||||||
|
log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
if (msr->of_status == OF_STATUS_COMPLETE) {
|
if (msr->of_status == OF_STATUS_COMPLETE) {
|
||||||
msr_log(msr, 1, "Output filter: Internal error: output filtering complete yet filter was invoked.");
|
msr_log(msr, 1, "Output filter: Internal error: output filtering complete yet filter was invoked.");
|
||||||
@ -452,6 +486,7 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
return APR_EGENERAL;
|
return APR_EGENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Loop through the buckets in the brigade in order
|
/* Loop through the buckets in the brigade in order
|
||||||
* to extract the size of the data available.
|
* to extract the size of the data available.
|
||||||
*/
|
*/
|
||||||
@ -490,6 +525,22 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (APR_BUCKET_IS_EOS(bucket)) {
|
if (APR_BUCKET_IS_EOS(bucket)) {
|
||||||
|
eos_bucket = bucket;
|
||||||
|
|
||||||
|
// Inject content (append & non-buffering).
|
||||||
|
if (msr->txcfg->content_injection_enabled && msr->content_append) {
|
||||||
|
apr_bucket *bucket_ci = NULL;
|
||||||
|
|
||||||
|
bucket_ci = apr_bucket_heap_create(msr->content_append,
|
||||||
|
msr->content_append_len, NULL, f->r->connection->bucket_alloc);
|
||||||
|
APR_BUCKET_INSERT_BEFORE(bucket, bucket_ci);
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Content-Injection (nb): Added content to bottom: %s",
|
||||||
|
log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
msr->of_done_reading = 1;
|
msr->of_done_reading = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,7 +592,6 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Why does the function below take pointer to length? Will it modify it?
|
// TODO Why does the function below take pointer to length? Will it modify it?
|
||||||
|
|
||||||
rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length);
|
rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length);
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
msr_log(msr, 1, "Output filter: Failed to flatten brigade (%i): %s", rc,
|
msr_log(msr, 1, "Output filter: Failed to flatten brigade (%i): %s", rc,
|
||||||
@ -567,6 +617,34 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
|
|||||||
if (msr->of_skipping == 0) {
|
if (msr->of_skipping == 0) {
|
||||||
record_time_checkpoint(msr, 3);
|
record_time_checkpoint(msr, 3);
|
||||||
|
|
||||||
|
// Inject content into response (prepend & buffering).
|
||||||
|
if (msr->txcfg->content_injection_enabled && msr->content_prepend) {
|
||||||
|
apr_bucket *bucket_ci = NULL;
|
||||||
|
|
||||||
|
bucket_ci = apr_bucket_heap_create(msr->content_prepend,
|
||||||
|
msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
|
||||||
|
APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci);
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Content Injection (b): Added content to top: %s",
|
||||||
|
log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject content into response (append & buffering).
|
||||||
|
if (msr->txcfg->content_injection_enabled && msr->content_append) {
|
||||||
|
apr_bucket *bucket_ci = NULL;
|
||||||
|
|
||||||
|
bucket_ci = apr_bucket_heap_create(msr->content_append,
|
||||||
|
msr->content_append_len, NULL, f->r->connection->bucket_alloc);
|
||||||
|
APR_BUCKET_INSERT_BEFORE(eos_bucket, bucket_ci);
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "Content-Injection (b): Added content to bottom: %s",
|
||||||
|
log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rc = ap_pass_brigade(f->next, msr->of_brigade);
|
rc = ap_pass_brigade(f->next, msr->of_brigade);
|
||||||
if (rc != APR_SUCCESS) {
|
if (rc != APR_SUCCESS) {
|
||||||
int log_level = 1;
|
int log_level = 1;
|
||||||
|
@ -309,6 +309,12 @@ struct modsec_rec {
|
|||||||
|
|
||||||
/* rule processing temp pool */
|
/* rule processing temp pool */
|
||||||
apr_pool_t *msc_rule_mptmp;
|
apr_pool_t *msc_rule_mptmp;
|
||||||
|
|
||||||
|
/* content injection */
|
||||||
|
const char *content_prepend;
|
||||||
|
apr_off_t content_prepend_len;
|
||||||
|
const char *content_append;
|
||||||
|
apr_off_t content_append_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct directory_config {
|
struct directory_config {
|
||||||
@ -386,6 +392,9 @@ struct directory_config {
|
|||||||
/* Misc */
|
/* Misc */
|
||||||
const char *data_dir;
|
const char *data_dir;
|
||||||
const char *webappid;
|
const char *webappid;
|
||||||
|
|
||||||
|
/* Content injection. */
|
||||||
|
int content_injection_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct error_message {
|
struct error_message {
|
||||||
|
@ -1363,6 +1363,26 @@ static apr_status_t msre_action_exec_execute(modsec_rec *msr, apr_pool_t *mptmp,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* prepend */
|
||||||
|
static apr_status_t msre_action_prepend_execute(modsec_rec *msr, apr_pool_t *mptmp,
|
||||||
|
msre_rule *rule, msre_action *action)
|
||||||
|
{
|
||||||
|
msr->content_prepend = action->param;
|
||||||
|
msr->content_prepend_len = strlen(action->param);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* append */
|
||||||
|
static apr_status_t msre_action_append_execute(modsec_rec *msr, apr_pool_t *mptmp,
|
||||||
|
msre_rule *rule, msre_action *action)
|
||||||
|
{
|
||||||
|
msr->content_append = action->param;
|
||||||
|
msr->content_append_len = strlen(action->param);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* -- */
|
/* -- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1813,4 +1833,28 @@ void msre_engine_register_default_actions(msre_engine *engine) {
|
|||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* prepend */
|
||||||
|
msre_engine_action_register(engine,
|
||||||
|
"prepend",
|
||||||
|
ACTION_NON_DISRUPTIVE,
|
||||||
|
1, 1,
|
||||||
|
NO_PLUS_MINUS,
|
||||||
|
ACTION_CARDINALITY_ONE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
msre_action_prepend_execute
|
||||||
|
);
|
||||||
|
|
||||||
|
/* append */
|
||||||
|
msre_engine_action_register(engine,
|
||||||
|
"append",
|
||||||
|
ACTION_NON_DISRUPTIVE,
|
||||||
|
1, 1,
|
||||||
|
NO_PLUS_MINUS,
|
||||||
|
ACTION_CARDINALITY_ONE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
msre_action_append_execute
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user