mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 21:36:00 +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
|
||||
-------------------------
|
||||
|
||||
* 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:
|
||||
@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->webappid = NOT_SET_P;
|
||||
|
||||
/* Content injection. */
|
||||
dcfg->content_injection_enabled = NOT_SET;
|
||||
|
||||
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
|
||||
? 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;
|
||||
}
|
||||
|
||||
@ -414,6 +421,9 @@ void init_directory_config(directory_config *dcfg) {
|
||||
/* Misc */
|
||||
if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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"
|
||||
),
|
||||
|
||||
AP_INIT_FLAG (
|
||||
"SecContentInjection",
|
||||
cmd_content_injection,
|
||||
NULL,
|
||||
CMD_SCOPE_ANY,
|
||||
"On or Off"
|
||||
),
|
||||
|
||||
AP_INIT_TAKE1 (
|
||||
"SecCookieFormat",
|
||||
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) {
|
||||
request_rec *r = f->r;
|
||||
modsec_rec *msr = (modsec_rec *)f->ctx;
|
||||
apr_bucket *bucket;
|
||||
apr_bucket *bucket = NULL, *eos_bucket = NULL;
|
||||
apr_status_t rc;
|
||||
|
||||
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). */
|
||||
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
|
||||
if (msr->of_status == OF_STATUS_COMPLETE) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* Loop through the buckets in the brigade in order
|
||||
* 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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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?
|
||||
|
||||
rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length);
|
||||
if (rc != APR_SUCCESS) {
|
||||
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) {
|
||||
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);
|
||||
if (rc != APR_SUCCESS) {
|
||||
int log_level = 1;
|
||||
|
@ -309,6 +309,12 @@ struct modsec_rec {
|
||||
|
||||
/* rule processing temp pool */
|
||||
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 {
|
||||
@ -386,6 +392,9 @@ struct directory_config {
|
||||
/* Misc */
|
||||
const char *data_dir;
|
||||
const char *webappid;
|
||||
|
||||
/* Content injection. */
|
||||
int content_injection_enabled;
|
||||
};
|
||||
|
||||
struct error_message {
|
||||
|
@ -1363,6 +1363,26 @@ static apr_status_t msre_action_exec_execute(modsec_rec *msr, apr_pool_t *mptmp,
|
||||
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
|
||||
);
|
||||
|
||||
/* 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