mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 21:36:00 +03:00
Implemented SecRequestBodyNoFilesLimit (#103).
This commit is contained in:
parent
fd5e4fb32c
commit
575e86388a
4
CHANGES
4
CHANGES
@ -1,7 +1,9 @@
|
||||
|
||||
26 Nov 2007 - 2.5.0-dev3
|
||||
29 Nov 2007 - 2.5.0-dev3
|
||||
------------------------
|
||||
|
||||
* Implemented SecRequestBodyNoFilesLimit.
|
||||
|
||||
* Enhance handling of the case where we run out of disk space while
|
||||
writing to audit log entry.
|
||||
|
||||
|
@ -34,6 +34,7 @@ void *create_directory_config(apr_pool_t *mp, char *path) {
|
||||
dcfg->reqbody_access = NOT_SET;
|
||||
dcfg->reqbody_inmemory_limit = NOT_SET;
|
||||
dcfg->reqbody_limit = NOT_SET;
|
||||
dcfg->reqbody_no_files_limit = NOT_SET;
|
||||
dcfg->resbody_access = NOT_SET;
|
||||
|
||||
dcfg->debuglog_name = NOT_SET_P;
|
||||
@ -221,6 +222,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) {
|
||||
? parent->reqbody_inmemory_limit : child->reqbody_inmemory_limit);
|
||||
merged->reqbody_limit = (child->reqbody_limit == NOT_SET
|
||||
? parent->reqbody_limit : child->reqbody_limit);
|
||||
merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET
|
||||
? parent->reqbody_no_files_limit : child->reqbody_no_files_limit);
|
||||
merged->resbody_access = (child->resbody_access == NOT_SET
|
||||
? parent->resbody_access : child->resbody_access);
|
||||
|
||||
@ -453,6 +456,7 @@ void init_directory_config(directory_config *dcfg) {
|
||||
if (dcfg->reqbody_inmemory_limit == NOT_SET)
|
||||
dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT;
|
||||
if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT;
|
||||
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->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
|
||||
@ -1022,6 +1026,22 @@ static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg, const cha
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, const char *p1) {
|
||||
directory_config *dcfg = (directory_config *)_dcfg;
|
||||
long int limit;
|
||||
|
||||
if (dcfg == NULL) return NULL;
|
||||
|
||||
limit = strtol(p1, NULL, 10);
|
||||
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
|
||||
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1);
|
||||
}
|
||||
|
||||
dcfg->reqbody_no_files_limit = limit;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) {
|
||||
directory_config *dcfg = (directory_config *)_dcfg;
|
||||
if (dcfg == NULL) return NULL;
|
||||
@ -1668,7 +1688,15 @@ const command_rec module_directives[] = {
|
||||
cmd_request_body_limit,
|
||||
NULL,
|
||||
CMD_SCOPE_ANY,
|
||||
"maximum request body size ModSecurity is allowed to access."
|
||||
"maximum request body size ModSecurity will accept."
|
||||
),
|
||||
|
||||
AP_INIT_TAKE1 (
|
||||
"SecRequestBodyNoFilesLimit",
|
||||
cmd_request_body_no_files_limit,
|
||||
NULL,
|
||||
CMD_SCOPE_ANY,
|
||||
"maximum request body size ModSecurity will accept, but excluding the size of uploaded files."
|
||||
),
|
||||
|
||||
AP_INIT_TAKE1 (
|
||||
|
@ -221,7 +221,14 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
|
||||
}
|
||||
|
||||
if (buflen != 0) {
|
||||
if (modsecurity_request_body_store(msr, buf, buflen, error_msg) < 0) {
|
||||
int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg);
|
||||
if (rcbs < 0) {
|
||||
if (rcbs == -5) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Requests body no files data length is larger than the "
|
||||
"configured limit (%lu).", msr->txcfg->reqbody_no_files_limit);
|
||||
return -5;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,7 @@ extern DSOLOCAL modsec_build_type_rec modsec_build_type[];
|
||||
#define REQUEST_BODY_HARD_LIMIT 1073741824L
|
||||
#define REQUEST_BODY_DEFAULT_INMEMORY_LIMIT 131072
|
||||
#define REQUEST_BODY_DEFAULT_LIMIT 134217728
|
||||
#define REQUEST_BODY_NO_FILES_DEFAULT_LIMIT 1048576
|
||||
#define RESPONSE_BODY_DEFAULT_LIMIT 524288
|
||||
#define RESPONSE_BODY_HARD_LIMIT 1073741824L
|
||||
|
||||
@ -306,6 +307,8 @@ struct modsec_rec {
|
||||
int msc_reqbody_error;
|
||||
const char *msc_reqbody_error_msg;
|
||||
|
||||
apr_size_t msc_reqbody_no_files_length;
|
||||
|
||||
multipart_data *mpd; /* MULTIPART processor data structure */
|
||||
|
||||
#ifdef WITH_LIBXML2
|
||||
@ -366,6 +369,7 @@ struct directory_config {
|
||||
int reqbody_access;
|
||||
long int reqbody_inmemory_limit;
|
||||
long int reqbody_limit;
|
||||
long int reqbody_no_files_limit;
|
||||
int resbody_access;
|
||||
|
||||
long int of_limit;
|
||||
|
@ -192,6 +192,9 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
|
||||
}
|
||||
}
|
||||
|
||||
/* The buffer is data so increase the data length counter. */
|
||||
msr->msc_reqbody_no_files_length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft);
|
||||
|
||||
if (len > 1) {
|
||||
if (msr->mpd->buf[len - 2] == '\r') {
|
||||
msr->mpd->flag_crlf_line = 1;
|
||||
@ -422,6 +425,9 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
|
||||
}
|
||||
else if (msr->mpd->mpp->type == MULTIPART_FORMDATA) {
|
||||
value_part_t *value_part = apr_pcalloc(msr->mp, sizeof(value_part_t));
|
||||
|
||||
/* The buffer contains data so increase the data length counter. */
|
||||
msr->msc_reqbody_no_files_length += (MULTIPART_BUF_SIZE - msr->mpd->bufleft) + msr->mpd->reserve[0];
|
||||
|
||||
/* add this part to the list of parts */
|
||||
|
||||
|
@ -25,7 +25,6 @@ static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char **
|
||||
msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp,
|
||||
32, sizeof(msc_data_chunk *));
|
||||
if (msr->msc_reqbody_chunks == NULL) {
|
||||
|
||||
*error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to prepare in-memory storage.");
|
||||
return -1;
|
||||
}
|
||||
@ -263,6 +262,11 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
||||
char *my_error_msg = NULL;
|
||||
|
||||
if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
||||
/* The per-request data length counter will
|
||||
* be updated by the multipart parser.
|
||||
*/
|
||||
|
||||
/* Process data as multipart/form-data. */
|
||||
if (multipart_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Request body processor error: %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
@ -273,6 +277,10 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
||||
#ifdef WITH_LIBXML2
|
||||
else
|
||||
if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
||||
/* Increase per-request data length counter. */
|
||||
msr->msc_reqbody_no_files_length += length;
|
||||
|
||||
/* Process data as XML. */
|
||||
if (xml_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Request body processor error: %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
@ -283,7 +291,10 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
||||
#endif
|
||||
else
|
||||
if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||
/* Do nothing, URLENCODED processor does not support streaming. */
|
||||
/* Increase per-request data length counter. */
|
||||
msr->msc_reqbody_no_files_length += length;
|
||||
|
||||
/* Do nothing else, URLENCODED processor does not support streaming. */
|
||||
}
|
||||
else {
|
||||
*error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
|
||||
@ -291,6 +302,11 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that we are not over the request body no files limit. */
|
||||
if (msr->msc_reqbody_no_files_length >= (unsigned long) msr->txcfg->reqbody_no_files_limit) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Store data. */
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||
@ -395,8 +411,10 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that we've read the body. */
|
||||
msr->msc_reqbody_read = 1;
|
||||
|
||||
/* Finalise body processing. */
|
||||
if ((msr->msc_reqbody_processor != NULL)&&(msr->msc_reqbody_error == 0)) {
|
||||
char *my_error_msg = NULL;
|
||||
|
||||
@ -432,6 +450,9 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Note the request body no files length. */
|
||||
msr_log(msr, 4, "Reqest body no files length: %lu", msr->msc_reqbody_no_files_length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1278,8 +1278,6 @@ SecAuditLogStorageDir logs/audit
|
||||
<para><emphasis>Example Usage:</emphasis> <literal
|
||||
moreinfo="none">SecRequestBodyLimit 134217728</literal></para>
|
||||
|
||||
<para><emphasis>Processing Phase:</emphasis> N/A</para>
|
||||
|
||||
<para><emphasis>Scope:</emphasis> Any</para>
|
||||
|
||||
<para><emphasis>Dependencies/Notes:</emphasis> 131072 KB (134217728
|
||||
@ -1287,6 +1285,36 @@ SecAuditLogStorageDir logs/audit
|
||||
with status code 413 Request Entity Too Large. There is a hard limit of
|
||||
1 GB.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal>SecRequestBodyNoFilesLimit</literal></title>
|
||||
|
||||
<para><emphasis>Description:</emphasis> Configures the maximum request
|
||||
body size ModSecurity will accept for buffering, excluding the size of
|
||||
files being transported in the request. This directive comes handy to
|
||||
further reduce susceptability to DoS attacks when someone is sending
|
||||
request bodies of very large sizes. Web applications that require file
|
||||
uploads must configure <literal>SecRequestBodyLimit</literal> to a
|
||||
high value. Since large files are streamed to disk file uploads will
|
||||
not increase memory consumption. However, it's still possible for
|
||||
someone to take advantage of a large request body limit and send
|
||||
non-upload requests with large body sizes. This directive eliminates
|
||||
that loophole. </para>
|
||||
|
||||
<para><emphasis>Syntax:</emphasis> <literal
|
||||
moreinfo="none">SecRequestBodyNoFilesLimit NUMBER_IN_BYTES</literal></para>
|
||||
|
||||
<para><emphasis>Example Usage:</emphasis> <literal
|
||||
moreinfo="none">SecRequestBodyLimit 131072</literal></para>
|
||||
|
||||
<para><emphasis>Scope:</emphasis> Any</para>
|
||||
|
||||
<para><emphasis>Dependencies/Notes:</emphasis> 1 MB (1048576
|
||||
bytes) is the default setting. This value is very conservative. For
|
||||
most applications you should be able to reduce it down to 128 KB or
|
||||
lower. Anything over the limit will be rejected with status code <literal>413
|
||||
Request Entity Too Large</literal>. There is a hard limit of 1 GB.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><literal>SecRequestBodyInMemoryLimit</literal></title>
|
||||
|
Loading…
x
Reference in New Issue
Block a user