mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-30 03:34:29 +03:00
Adds support for basic Multipart process
Adjustments will be needed, for instance: the logging support is still missing
This commit is contained in:
@@ -110,6 +110,32 @@ class Assay {
|
|||||||
int processURI(const char *uri, const char *protocol,
|
int processURI(const char *uri, const char *protocol,
|
||||||
const char *http_version);
|
const char *http_version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of request body that ModSecurity may give a special treatment
|
||||||
|
* for the data.
|
||||||
|
*/
|
||||||
|
enum RequestBodyType {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UnknownFormat,
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
MultiPartRequestBody,
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
WWWFormUrlEncoded,
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
JSONRequestBody,
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
XMLRequestBody
|
||||||
|
};
|
||||||
|
|
||||||
int processRequestHeaders();
|
int processRequestHeaders();
|
||||||
int addRequestHeader(const std::string& key, const std::string& value);
|
int addRequestHeader(const std::string& key, const std::string& value);
|
||||||
@@ -185,6 +211,7 @@ class Assay {
|
|||||||
double m_ARGScombinedSize;
|
double m_ARGScombinedSize;
|
||||||
/** TODO: Support to save double in the storage. */
|
/** TODO: Support to save double in the storage. */
|
||||||
std::string *m_ARGScombinedSizeStr;
|
std::string *m_ARGScombinedSizeStr;
|
||||||
|
RequestBodyType m_requestBodyType;
|
||||||
|
|
||||||
std::ostringstream m_requestBody;
|
std::ostringstream m_requestBody;
|
||||||
std::ostringstream m_responseBody;
|
std::ostringstream m_responseBody;
|
||||||
|
@@ -91,6 +91,8 @@ libmodsecurity_la_SOURCES = \
|
|||||||
rules.cc \
|
rules.cc \
|
||||||
utils.cc \
|
utils.cc \
|
||||||
debug_log.cc \
|
debug_log.cc \
|
||||||
|
request_body_processor/multipart.cc \
|
||||||
|
request_body_processor/multipart_blob.cc \
|
||||||
rule.cc \
|
rule.cc \
|
||||||
unique_id.cc \
|
unique_id.cc \
|
||||||
variable.cc \
|
variable.cc \
|
||||||
|
46
src/assay.cc
46
src/assay.cc
@@ -34,8 +34,10 @@
|
|||||||
#include "src/utils.h"
|
#include "src/utils.h"
|
||||||
#include "src/audit_log.h"
|
#include "src/audit_log.h"
|
||||||
#include "src/unique_id.h"
|
#include "src/unique_id.h"
|
||||||
|
#include "request_body_processor/multipart.h"
|
||||||
|
|
||||||
using ModSecurity::actions::Action;
|
using ModSecurity::actions::Action;
|
||||||
|
using ModSecurity::RequestBodyProcessor::Multipart;
|
||||||
|
|
||||||
namespace ModSecurity {
|
namespace ModSecurity {
|
||||||
|
|
||||||
@@ -95,6 +97,7 @@ Assay::Assay(ModSecurity *ms, Rules *rules)
|
|||||||
m_namesArgs(NULL),
|
m_namesArgs(NULL),
|
||||||
m_namesArgsPost(NULL),
|
m_namesArgsPost(NULL),
|
||||||
m_namesArgsGet(NULL),
|
m_namesArgsGet(NULL),
|
||||||
|
m_requestBodyType(UnknownFormat),
|
||||||
start(std::chrono::system_clock::now()),
|
start(std::chrono::system_clock::now()),
|
||||||
m_ms(ms) {
|
m_ms(ms) {
|
||||||
id = std::to_string(this->timeStamp) + \
|
id = std::to_string(this->timeStamp) + \
|
||||||
@@ -311,6 +314,25 @@ int Assay::addRequestHeader(const std::string& key,
|
|||||||
this->store_variable("AUTH_TYPE", type[0]);
|
this->store_variable("AUTH_TYPE", type[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple check to decide the request body content. This is not the right
|
||||||
|
* place, the "body processor" should be able to tell what he is capable
|
||||||
|
* to deal with.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (tolower(key) == "content-type") {
|
||||||
|
std::string multipart("multipart/form-data");
|
||||||
|
std::string l = tolower(value);
|
||||||
|
|
||||||
|
if (l.compare(0, multipart.length(), multipart) == 0) {
|
||||||
|
this->m_requestBodyType = MultiPartRequestBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l == "application/x-www-form-urlencoded") {
|
||||||
|
this->m_requestBodyType = WWWFormUrlEncoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +413,26 @@ int Assay::addRequestHeader(const unsigned char *key, size_t key_n,
|
|||||||
int Assay::processRequestBody() {
|
int Assay::processRequestBody() {
|
||||||
debug(4, "Starting phase REQUEST_BODY. (SecRules 2)");
|
debug(4, "Starting phase REQUEST_BODY. (SecRules 2)");
|
||||||
|
|
||||||
if (m_requestBody.tellp() > 0) {
|
if (m_requestBody.tellp() <= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_requestBodyType == MultiPartRequestBody) {
|
||||||
|
std::string *a = resolve_variable_first("REQUEST_HEADERS:Content-Type");
|
||||||
|
if (a != NULL) {
|
||||||
|
Multipart m(*a);
|
||||||
|
m.init();
|
||||||
|
m.process(m_requestBody.str());
|
||||||
|
for (auto &a : m.variables) {
|
||||||
|
store_variable(a.first, a.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_requestBodyType == WWWFormUrlEncoded) {
|
||||||
|
std::string content = uri_decode(m_requestBody.str());
|
||||||
|
content.erase(content.length()-1, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIXME:
|
* FIXME:
|
||||||
*
|
*
|
||||||
@@ -399,9 +440,6 @@ int Assay::processRequestBody() {
|
|||||||
* the secrules said about it.
|
* the secrules said about it.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
std::string content = uri_decode(m_requestBody.str());
|
|
||||||
content.erase(content.length()-1, 1);
|
|
||||||
|
|
||||||
char sep1 = '&';
|
char sep1 = '&';
|
||||||
const char *pos = strchr(content.c_str(), '?');
|
const char *pos = strchr(content.c_str(), '?');
|
||||||
|
|
||||||
|
@@ -56,7 +56,7 @@ OPERATORNOARG (?i:@detectSQLi|@detectXSS|@geoLookup|@validateUrlEncoding|@valida
|
|||||||
|
|
||||||
TRANSFORMATION t:(lowercase|urlDecodeUni|urlDecode|none|compressWhitespace|removeWhitespace|replaceNulls|removeNulls|htmlEntityDecode|jsDecode|cssDecode|trim)
|
TRANSFORMATION t:(lowercase|urlDecodeUni|urlDecode|none|compressWhitespace|removeWhitespace|replaceNulls|removeNulls|htmlEntityDecode|jsDecode|cssDecode|trim)
|
||||||
|
|
||||||
VARIABLE (?i:AUTH_TYPE|ARGS_NAMES|ARGS|QUERY_STRING|REMOTE_ADDR|REQUEST_BASENAME|REQUEST_BODY|REQUEST_COOKIES_NAMES|REQUEST_COOKIES|REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|REQUEST_METHOD|REQUEST_PROTOCOL|REQUEST_URI|RESPONSE_BODY|RESPONSE_CONTENT_LENGTH|RESPONSE_CONTENT_TYPE|RESPONSE_HEADERS_NAMES|RESPONSE_HEADERS|RESPONSE_PROTOCOL|RESPONSE_STATUS|TX)
|
VARIABLE (?i:FILES|AUTH_TYPE|ARGS_NAMES|ARGS|QUERY_STRING|REMOTE_ADDR|REQUEST_BASENAME|REQUEST_BODY|REQUEST_COOKIES_NAMES|REQUEST_COOKIES|REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|REQUEST_METHOD|REQUEST_PROTOCOL|REQUEST_URI|RESPONSE_BODY|RESPONSE_CONTENT_LENGTH|RESPONSE_CONTENT_TYPE|RESPONSE_HEADERS_NAMES|RESPONSE_HEADERS|RESPONSE_PROTOCOL|RESPONSE_STATUS|TX)
|
||||||
RUN_TIME_VAR_DUR (?i:DURATION)
|
RUN_TIME_VAR_DUR (?i:DURATION)
|
||||||
RUN_TIME_VAR_ENV (?i:ENV)
|
RUN_TIME_VAR_ENV (?i:ENV)
|
||||||
|
|
||||||
|
221
src/request_body_processor/multipart.cc
Normal file
221
src/request_body_processor/multipart.cc
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2015 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 "request_body_processor/multipart.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "request_body_processor/multipart_blob.h"
|
||||||
|
|
||||||
|
namespace ModSecurity {
|
||||||
|
namespace RequestBodyProcessor {
|
||||||
|
|
||||||
|
Multipart::Multipart(std:: string header)
|
||||||
|
: m_boundaryStartsWithWhiteSpace(false),
|
||||||
|
m_boundaryIsQuoted(false),
|
||||||
|
m_header(header) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Multipart::init() {
|
||||||
|
if (m_header.length() > 1024) {
|
||||||
|
debug(4, "Multipart: Invalid boundary in Content-Type (length).");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t boundary_pos = m_header.find("boundary");
|
||||||
|
if (boundary_pos < 0) {
|
||||||
|
if (boundary_pos > 0 && m_header.find("boundary", boundary_pos) > 0) {
|
||||||
|
debug(4, "Multipart: Multiple boundary parameters in " \
|
||||||
|
"Content-Type.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string boundary = m_header.c_str() + boundary_pos;
|
||||||
|
std::size_t semicolon_pos = boundary.find(";");
|
||||||
|
if (semicolon_pos != std::string::npos
|
||||||
|
&& boundary.find(";", semicolon_pos + 1) != std::string::npos) {
|
||||||
|
debug(4, "Multipart: Invalid boundary in Content-Type. (malformed). " \
|
||||||
|
"Too many semicolons.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (semicolon_pos < 0) {
|
||||||
|
debug(4, "Multipart: Missing semicolon.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boundary.at(8) != '=') {
|
||||||
|
debug(4, "Multipart: Invalid boundary in Content-Type. (malformed). " \
|
||||||
|
"Missing equals.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
Not checked.
|
||||||
|
/* Check parameter name ends well. */
|
||||||
|
if (b != (msr->mpd->boundary + 8)) {
|
||||||
|
/* Check all characters between the end of the boundary
|
||||||
|
* and the = character.
|
||||||
|
*/
|
||||||
|
for (p = msr->mpd->boundary + 8; p < b; p++) {
|
||||||
|
if (isspace(*p)) {
|
||||||
|
/* Flag for whitespace after parameter name. */
|
||||||
|
msr->mpd->flag_boundary_whitespace = 1;
|
||||||
|
} else {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: " \
|
||||||
|
"Invalid boundary in C-T (parameter name).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b++; /* Go over the = character. */
|
||||||
|
len = strlen(b);
|
||||||
|
|
||||||
|
/* Flag for whitespace before parameter value. */
|
||||||
|
if (isspace(*b)) {
|
||||||
|
msr->mpd->flag_boundary_whitespace = 1;
|
||||||
|
}
|
||||||
|
#endif // if 0
|
||||||
|
if (boundary.at(8 + 1) == ' ') {
|
||||||
|
m_boundaryStartsWithWhiteSpace = true;
|
||||||
|
debug(4, "Multipart: Boundary starts with a white space");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_boundaryStartsWithWhiteSpace && boundary.at(8 + 2) == '"') ||
|
||||||
|
(!m_boundaryStartsWithWhiteSpace && boundary.at(8 + 1) == '"')) {
|
||||||
|
m_boundaryIsQuoted = true;
|
||||||
|
debug(4, "Multipart: Boundary inside quotes");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_boundaryIsQuoted && boundary.at(boundary.length()-1) != '"') {
|
||||||
|
debug(4, "Multipart: Invalid boundary in Content-type (quote).");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
Not checking
|
||||||
|
/* Case-insensitive test for the string "boundary" in the boundary. */
|
||||||
|
if (count_boundary_params(msr->mp, msr->mpd->boundary) != 0) {
|
||||||
|
msr->mpd->flag_error = 1;
|
||||||
|
*error_msg = apr_psprintf(msr->mp, "Multipart: Invalid boundary " \
|
||||||
|
"in C-T (content).");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // if 0
|
||||||
|
|
||||||
|
int real_boundary_pos = 9;
|
||||||
|
|
||||||
|
if (m_boundaryStartsWithWhiteSpace) {
|
||||||
|
real_boundary_pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_boundaryIsQuoted) {
|
||||||
|
real_boundary_pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_boundary = boundary.c_str() + real_boundary_pos;
|
||||||
|
|
||||||
|
if (m_boundaryIsQuoted) {
|
||||||
|
m_boundary.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boundaryContainsOnlyValidCharacters() == false) {
|
||||||
|
debug(4, "Multipart: Invalid boundary in Content-type " \
|
||||||
|
"(invalid characters).");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Multipart::boundaryContainsOnlyValidCharacters() {
|
||||||
|
if (m_boundary.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_boundary.length(); i++) {
|
||||||
|
int c = m_boundary.at(i);
|
||||||
|
|
||||||
|
/* Control characters and space not allowed. */
|
||||||
|
/* Non-ASCII characters not allowed. */
|
||||||
|
if (c < 32 || c > 126) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
/* Special characters not allowed. */
|
||||||
|
case '(' :
|
||||||
|
case ')' :
|
||||||
|
case '<' :
|
||||||
|
case '>' :
|
||||||
|
case '@' :
|
||||||
|
case ',' :
|
||||||
|
case ';' :
|
||||||
|
case ':' :
|
||||||
|
case '\\' :
|
||||||
|
case '"' :
|
||||||
|
case '/' :
|
||||||
|
case '[' :
|
||||||
|
case ']' :
|
||||||
|
case '?' :
|
||||||
|
case '=' :
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Multipart::process(std::string data) {
|
||||||
|
std::list<std::string> blobs;
|
||||||
|
size_t start = data.find(m_boundary);
|
||||||
|
size_t endl = 1;
|
||||||
|
|
||||||
|
if (start != 0) {
|
||||||
|
debug(4, "Multipart: Boundary was not the first thing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (start != std::string::npos) {
|
||||||
|
size_t end = data.find(m_boundary, start + m_boundary.length());
|
||||||
|
if (end == std::string::npos) {
|
||||||
|
start = end;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string block = std::string(data, start + m_boundary.length() +
|
||||||
|
+ endl, end - (start + m_boundary.length() + endl) - endl);
|
||||||
|
blobs.push_back(block);
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::string x : blobs) {
|
||||||
|
MultipartBlob m(x, this);
|
||||||
|
|
||||||
|
if (m.filename.empty() == false) {
|
||||||
|
variables.emplace("FILES:" + m.name, m.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace RequestBodyProcessor
|
||||||
|
} // namespace ModSecurity
|
52
src/request_body_processor/multipart.h
Normal file
52
src/request_body_processor/multipart.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2015 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 <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_
|
||||||
|
#define SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_
|
||||||
|
|
||||||
|
#include "modsecurity/assay.h"
|
||||||
|
|
||||||
|
namespace ModSecurity {
|
||||||
|
namespace RequestBodyProcessor {
|
||||||
|
|
||||||
|
class Multipart {
|
||||||
|
public:
|
||||||
|
explicit Multipart(std::string header);
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
bool boundaryContainsOnlyValidCharacters();
|
||||||
|
bool conuntBoundaryParameters();
|
||||||
|
bool process(std::string data);
|
||||||
|
|
||||||
|
ModSecurityStringVariables variables;
|
||||||
|
private:
|
||||||
|
void debug(int a, std::string str) {
|
||||||
|
std::cout << "Debug: " << str << std::endl;
|
||||||
|
}
|
||||||
|
std::string m_boundary;
|
||||||
|
std::string m_header;
|
||||||
|
|
||||||
|
bool m_boundaryStartsWithWhiteSpace = false;
|
||||||
|
bool m_boundaryIsQuoted = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RequestBodyProcessor
|
||||||
|
} // namespace ModSecurity
|
||||||
|
|
||||||
|
#endif // SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_
|
121
src/request_body_processor/multipart_blob.cc
Normal file
121
src/request_body_processor/multipart_blob.cc
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2015 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 "request_body_processor/multipart_blob.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace ModSecurity {
|
||||||
|
namespace RequestBodyProcessor {
|
||||||
|
|
||||||
|
MultipartBlob::MultipartBlob(const std::string &blob, Multipart *parent)
|
||||||
|
: m_blob(blob),
|
||||||
|
m_parent(parent) {
|
||||||
|
processContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MultipartBlob::processContent() {
|
||||||
|
size_t end = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
end = m_blob.find("\n", offset);
|
||||||
|
if (end == std::string::npos) {
|
||||||
|
debug(4, "Missing end of line");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string firstLine = std::string(m_blob, offset, end);
|
||||||
|
|
||||||
|
offset = end + 1;
|
||||||
|
end = m_blob.find("\n", offset);
|
||||||
|
if (end == std::string::npos) {
|
||||||
|
debug(4, "Missing end of line");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string secondLine = std::string(m_blob, offset, end - offset);
|
||||||
|
|
||||||
|
bool dispositionLine = processContentDispositionLine(firstLine);
|
||||||
|
if (dispositionLine == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contentTypeLine = processContentTypeLine(secondLine);
|
||||||
|
if (dispositionLine == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = end + 1;
|
||||||
|
if (contentType.empty() == false) {
|
||||||
|
end = m_blob.find_first_of("\n", offset);
|
||||||
|
if (end == std::string::npos) {
|
||||||
|
debug(4, "Missing end of line");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset = end + 1;
|
||||||
|
}
|
||||||
|
content = std::string(m_blob, offset, m_blob.length() - offset + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MultipartBlob::processContentTypeLine(
|
||||||
|
const std::string &contentTypeLine) {
|
||||||
|
size_t contentTypeKeyLength = 14;
|
||||||
|
|
||||||
|
if (contentTypeLine.length() <= contentTypeKeyLength) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType = std::string(contentTypeLine, contentTypeKeyLength,
|
||||||
|
contentTypeLine.length() - contentTypeKeyLength);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MultipartBlob::processContentDispositionLine(
|
||||||
|
const std::string &dispositionLine) {
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (dispositionLine.compare(21, 9, "form-data") != 0) {
|
||||||
|
debug(4, "Multipart: Content-Disposition is unknown");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find name=
|
||||||
|
offset = dispositionLine.find("name=");
|
||||||
|
if (offset != std::string::npos) {
|
||||||
|
offset = offset + 5 /* name= */ + 1 /* " */;
|
||||||
|
size_t end = dispositionLine.find("\"", offset);
|
||||||
|
if (end != std::string::npos) {
|
||||||
|
name = std::string(dispositionLine, offset, end - offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find filename=
|
||||||
|
offset = dispositionLine.find("filename=");
|
||||||
|
if (offset != std::string::npos) {
|
||||||
|
offset = offset + 9 /* filename= */ + 1 /* " */;
|
||||||
|
size_t end = dispositionLine.find("\"", offset);
|
||||||
|
if (end != std::string::npos) {
|
||||||
|
filename = std::string(dispositionLine, offset, end - offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace RequestBodyProcessor
|
||||||
|
} // namespace ModSecurity
|
51
src/request_body_processor/multipart_blob.h
Normal file
51
src/request_body_processor/multipart_blob.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2015 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 <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "request_body_processor/multipart.h"
|
||||||
|
|
||||||
|
#ifndef SRC_REQUEST_BODY_PROCESSOR_MULTIPART_BLOB_H_
|
||||||
|
#define SRC_REQUEST_BODY_PROCESSOR_MULTIPART_BLOB_H_
|
||||||
|
|
||||||
|
namespace ModSecurity {
|
||||||
|
namespace RequestBodyProcessor {
|
||||||
|
|
||||||
|
class MultipartBlob {
|
||||||
|
public:
|
||||||
|
explicit MultipartBlob(const std::string &blob, Multipart *parent);
|
||||||
|
|
||||||
|
bool processContent();
|
||||||
|
bool processContentDispositionLine(const std::string &dispositionLine);
|
||||||
|
bool processContentTypeLine(const std::string &contentTypeLine);
|
||||||
|
|
||||||
|
void debug(int a, std::string str) {
|
||||||
|
std::cout << "Debug: " << str << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string filename;
|
||||||
|
std::string contentType;
|
||||||
|
std::string content;
|
||||||
|
private:
|
||||||
|
const std::string m_blob;
|
||||||
|
Multipart *m_parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RequestBodyProcessor
|
||||||
|
} // namespace ModSecurity
|
||||||
|
|
||||||
|
#endif // SRC_REQUEST_BODY_PROCESSOR_MULTIPART_BLOB_H_
|
Reference in New Issue
Block a user