mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
Adds XML variable, xml body request processor and @validateSchema
This commit is contained in:
@@ -56,7 +56,8 @@ VARIABLES = \
|
||||
variables/tx.cc \
|
||||
variables/variable.cc \
|
||||
variables/variations/count.cc \
|
||||
variables/variations/exclusion.cc
|
||||
variables/variations/exclusion.cc \
|
||||
variables/xml.cc
|
||||
|
||||
|
||||
ACTIONS = \
|
||||
@@ -179,6 +180,12 @@ COLLECTION = \
|
||||
collection/backend/in_memory-per_process.cc
|
||||
|
||||
|
||||
BODY_PROCESSORS = \
|
||||
request_body_processor/multipart.cc \
|
||||
request_body_processor/multipart_blob.cc \
|
||||
request_body_processor/xml.cc
|
||||
|
||||
|
||||
libmodsecurity_la_SOURCES = \
|
||||
parser/seclang-parser.yy \
|
||||
parser/seclang-scanner.ll \
|
||||
@@ -196,10 +203,9 @@ libmodsecurity_la_SOURCES = \
|
||||
debug_log_writer.cc \
|
||||
debug_log_writer_agent.cc \
|
||||
macro_expansion.cc \
|
||||
request_body_processor/multipart.cc \
|
||||
request_body_processor/multipart_blob.cc \
|
||||
rule.cc \
|
||||
unique_id.cc \
|
||||
${BODY_PROCESSORS} \
|
||||
${ACTIONS} \
|
||||
${COLLECTION} \
|
||||
${OPERATORS} \
|
||||
@@ -221,16 +227,18 @@ libmodsecurity_la_CPPFLAGS = \
|
||||
$(GLOBAL_CPPFLAGS) \
|
||||
$(MODSEC_NO_LOGS) \
|
||||
$(YAJL_CFLAGS) \
|
||||
$(PCRE_CFLAGS)
|
||||
$(PCRE_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS)
|
||||
|
||||
libmodsecurity_la_LIBADD = \
|
||||
$(GLOBAL_LDADD) \
|
||||
$(CURL_LDADD) \
|
||||
$(GEOIP_LDFLAGS) $(GEOIP_LDADD) \
|
||||
@LEXLIB@ \
|
||||
$(PCRE_LDADD) \
|
||||
$(YAJL_LDADD) \
|
||||
../others/libinjection.la
|
||||
$(GLOBAL_LDADD) \
|
||||
$(CURL_LDADD) \
|
||||
$(GEOIP_LDFLAGS) $(GEOIP_LDADD) \
|
||||
@LEXLIB@ \
|
||||
$(PCRE_LDADD) \
|
||||
$(YAJL_LDADD) \
|
||||
$(LIBXML2_LDADD) \
|
||||
../others/libinjection.la
|
||||
|
||||
|
||||
libmodsecurity_la_LDFLAGS = \
|
||||
|
@@ -18,26 +18,116 @@
|
||||
#include <string>
|
||||
|
||||
#include "operators/operator.h"
|
||||
#include "request_body_processor/xml.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
|
||||
namespace modsecurity {
|
||||
namespace operators {
|
||||
|
||||
bool ValidateSchema::evaluate(Transaction *transaction,
|
||||
const std::string &str) {
|
||||
/**
|
||||
* @todo Implement the operator ValidateSchema.
|
||||
* Reference: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#validateSchema
|
||||
*/
|
||||
bool ValidateSchema::init(const std::string &file, const char **error) {
|
||||
m_resource = find_resource(param, file);
|
||||
if (m_resource == "") {
|
||||
std::string f("XML: File not found: " + param + ".");
|
||||
*error = strdup(f.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_parserCtx = xmlSchemaNewParserCtxt(m_resource.c_str());
|
||||
if (m_parserCtx == NULL) {
|
||||
std::stringstream err;
|
||||
err << "XML: Failed to load Schema from file: ";
|
||||
err << m_resource;
|
||||
err << ". ";
|
||||
if (m_err.empty() == false) {
|
||||
err << m_err;
|
||||
}
|
||||
*error = strdup(err.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
xmlSchemaSetParserErrors(m_parserCtx,
|
||||
(xmlSchemaValidityErrorFunc)error_load,
|
||||
(xmlSchemaValidityWarningFunc)warn_load, &m_err);
|
||||
|
||||
xmlThrDefSetGenericErrorFunc(m_parserCtx,
|
||||
null_error);
|
||||
|
||||
xmlSetGenericErrorFunc(m_parserCtx,
|
||||
null_error);
|
||||
|
||||
m_schema = xmlSchemaParse(m_parserCtx);
|
||||
if (m_schema == NULL) {
|
||||
std::stringstream err;
|
||||
err << "XML: Failed to load Schema: ";
|
||||
err << m_resource;
|
||||
err << ".";
|
||||
if (m_err.empty() == false) {
|
||||
err << " " << m_err;
|
||||
}
|
||||
*error = strdup(err.str().c_str());
|
||||
xmlSchemaFreeParserCtxt(m_parserCtx);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_validCtx = xmlSchemaNewValidCtxt(m_schema);
|
||||
if (m_validCtx == NULL) {
|
||||
std::stringstream err("XML: Failed to create validation context.");
|
||||
if (m_err.empty() == false) {
|
||||
err << " " << m_err;
|
||||
}
|
||||
*error = strdup(err.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
ValidateSchema::ValidateSchema(std::string op, std::string param,
|
||||
bool negation)
|
||||
: Operator() {
|
||||
this->op = op;
|
||||
this->param = param;
|
||||
bool ValidateSchema::evaluate(Transaction *t,
|
||||
const std::string &str) {
|
||||
int rc;
|
||||
|
||||
/* Send validator errors/warnings to msr_log */
|
||||
xmlSchemaSetValidErrors(m_validCtx,
|
||||
(xmlSchemaValidityErrorFunc)error_runtime,
|
||||
(xmlSchemaValidityWarningFunc)warn_runtime, t);
|
||||
|
||||
if (t->m_xml->m_data.doc == NULL) {
|
||||
t->debug(4, "XML document tree could not be found for " \
|
||||
"schema validation.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t->m_xml->m_data.well_formed != 1) {
|
||||
t->debug(4, "XML: Schema validation failed because " \
|
||||
"content is not well formed.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Make sure there were no other generic processing errors */
|
||||
/*
|
||||
if (msr->msc_reqbody_error) {
|
||||
t->debug(4, "XML: Schema validation could not proceed due to previous"
|
||||
" processing errors.");
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
rc = xmlSchemaValidateDoc(m_validCtx, t->m_xml->m_data.doc);
|
||||
if (rc != 0) {
|
||||
t->debug(4, "XML: Schema validation failed.");
|
||||
xmlSchemaFree(m_schema);
|
||||
xmlSchemaFreeParserCtxt(m_parserCtx);
|
||||
return true; /* No match. */
|
||||
}
|
||||
|
||||
t->debug(4, "XML: Successfully validated payload against " \
|
||||
"Schema: " + m_resource);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace operators
|
||||
} // namespace modsecurity
|
||||
|
@@ -16,6 +16,12 @@
|
||||
#ifndef SRC_OPERATORS_VALIDATE_SCHEMA_H_
|
||||
#define SRC_OPERATORS_VALIDATE_SCHEMA_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <libxml/xmlschemas.h>
|
||||
#include <libxml/xpath.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "operators/operator.h"
|
||||
@@ -27,8 +33,100 @@ namespace operators {
|
||||
class ValidateSchema : public Operator {
|
||||
public:
|
||||
/** @ingroup ModSecurity_Operator */
|
||||
ValidateSchema(std::string o, std::string p, bool i);
|
||||
ValidateSchema(std::string o, std::string p, bool i)
|
||||
: Operator(o, p, i),
|
||||
m_schema(NULL),
|
||||
m_validCtx(NULL),
|
||||
m_parserCtx(NULL) { }
|
||||
~ValidateSchema() {
|
||||
/*
|
||||
if (m_schema != NULL) {
|
||||
xmlSchemaFree(m_schema);
|
||||
m_schema = NULL;
|
||||
}
|
||||
*/
|
||||
if (m_validCtx != NULL) {
|
||||
xmlSchemaFreeValidCtxt(m_validCtx);
|
||||
m_validCtx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool evaluate(Transaction *transaction, const std::string &str) override;
|
||||
bool init(const std::string &file, const char **error) override;
|
||||
|
||||
|
||||
static void error_load(void *ctx, const char *msg, ...) {
|
||||
std::string *t = reinterpret_cast<std::string *>(ctx);
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
|
||||
va_start(args, msg);
|
||||
int len = vsnprintf(buf, sizeof(buf), msg, args);
|
||||
va_end(args);
|
||||
|
||||
if (len > 0) {
|
||||
t->append("XML Error: " + std::string(buf));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void warn_load(void *ctx, const char *msg, ...) {
|
||||
std::string *t = reinterpret_cast<std::string *>(ctx);
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
|
||||
va_start(args, msg);
|
||||
int len = vsnprintf(buf, sizeof(buf), msg, args);
|
||||
va_end(args);
|
||||
|
||||
if (len > 0) {
|
||||
t->append("XML Warning: " + std::string(buf));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void error_runtime(void *ctx, const char *msg, ...) {
|
||||
Transaction *t = reinterpret_cast<Transaction *>(ctx);
|
||||
char buf[1024];
|
||||
std::string s;
|
||||
va_list args;
|
||||
|
||||
va_start(args, msg);
|
||||
int len = vsnprintf(buf, sizeof(buf), msg, args);
|
||||
va_end(args);
|
||||
|
||||
if (len > 0) {
|
||||
s = "XML Error: " + std::string(buf);
|
||||
}
|
||||
t->debug(4, s);
|
||||
}
|
||||
|
||||
|
||||
static void warn_runtime(void *ctx, const char *msg, ...) {
|
||||
Transaction *t = reinterpret_cast<Transaction *>(ctx);
|
||||
char buf[1024];
|
||||
std::string s;
|
||||
va_list args;
|
||||
|
||||
va_start(args, msg);
|
||||
int len = vsnprintf(buf, sizeof(buf), msg, args);
|
||||
va_end(args);
|
||||
|
||||
if (len > 0) {
|
||||
s = "XML Warning: " + std::string(buf);
|
||||
}
|
||||
t->debug(4, s);
|
||||
}
|
||||
|
||||
static void null_error(void *ctx, const char *msg, ...) {
|
||||
}
|
||||
|
||||
private:
|
||||
xmlSchemaParserCtxtPtr m_parserCtx;
|
||||
xmlSchemaValidCtxtPtr m_validCtx;
|
||||
xmlSchemaPtr m_schema;
|
||||
std::string m_resource;
|
||||
std::string m_err;
|
||||
};
|
||||
|
||||
} // namespace operators
|
||||
|
@@ -61,6 +61,7 @@ class Driver;
|
||||
#include "variables/time_wday.h"
|
||||
#include "variables/time_year.h"
|
||||
#include "variables/tx.h"
|
||||
#include "variables/xml.h"
|
||||
|
||||
using modsecurity::ModSecurity;
|
||||
|
||||
@@ -103,6 +104,7 @@ using modsecurity::Variables::TimeWDay;
|
||||
using modsecurity::Variables::TimeYear;
|
||||
using modsecurity::Variables::Variable;
|
||||
using modsecurity::Variables::Tx;
|
||||
using modsecurity::Variables::XML;
|
||||
|
||||
|
||||
#define CHECK_VARIATION_DECL \
|
||||
@@ -229,6 +231,7 @@ using modsecurity::Variables::Tx;
|
||||
%token <std::string> RUN_TIME_VAR_TIME_SEC
|
||||
%token <std::string> RUN_TIME_VAR_TIME_WDAY
|
||||
%token <std::string> RUN_TIME_VAR_TIME_YEAR
|
||||
%token <std::string> RUN_TIME_VAR_XML
|
||||
|
||||
%token <std::string> CONFIG_SEC_REMOTE_RULES_FAIL_ACTION
|
||||
|
||||
@@ -816,6 +819,15 @@ var:
|
||||
if (!var) { var = new TimeYear(name); }
|
||||
$$ = var;
|
||||
}
|
||||
| RUN_TIME_VAR_XML
|
||||
{
|
||||
std::string name($1);
|
||||
CHECK_VARIATION_DECL
|
||||
CHECK_VARIATION(&) { var = new Count(new XML(name)); }
|
||||
CHECK_VARIATION(!) { var = new Exclusion(new XML(name)); }
|
||||
if (!var) { var = new XML(name); }
|
||||
$$ = var;
|
||||
}
|
||||
;
|
||||
|
||||
act:
|
||||
|
@@ -117,7 +117,7 @@ TRANSFORMATION t:(?i:(cmdLine|sha1|hexEncode|lowercase|urlDecodeUni|urlDecode|n
|
||||
|
||||
|
||||
VARIABLE (?i:(RESOURCE|ARGS_COMBINED_SIZE|ARGS_GET_NAMES|ARGS_POST_NAMES|FILES_COMBINED_SIZE|FULL_REQUEST_LENGTH|REQUEST_BODY_LENGTH|REQUEST_URI_RAW|UNIQUE_ID|SERVER_PORT|SERVER_ADDR|REMOTE_PORT|REMOTE_HOST|MULTIPART_STRICT_ERROR|PATH_INFO|MULTIPART_CRLF_LF_LINES|MATCHED_VAR_NAME|MATCHED_VAR|INBOUND_DATA_ERROR|OUTBOUND_DATA_ERROR|FULL_REQUEST|AUTH_TYPE|ARGS_NAMES|REMOTE_ADDR|REQUEST_BASENAME|REQUEST_BODY|REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_METHOD|REQUEST_PROTOCOL|REQUEST_URI|RESPONSE_BODY|RESPONSE_CONTENT_LENGTH|RESPONSE_CONTENT_TYPE|RESPONSE_HEADERS_NAMES|RESPONSE_PROTOCOL|RESPONSE_STATUS|REQBODY_PROCESSOR|USERID|SESSIONID))
|
||||
VARIABLE_COL (?i:(SESSION|GLOBAL|ARGS_POST|ARGS_GET|ARGS|FILES_SIZES|FILES_NAMES|FILES_TMP_CONTENT|MULTIPART_FILENAME|MULTIPART_NAME|MATCHED_VARS_NAMES|MATCHED_VARS|FILES|QUERY_STRING|REQUEST_COOKIES|REQUEST_HEADERS|RESPONSE_HEADERS|GEO|IP|XML|REQUEST_COOKIES_NAMES))
|
||||
VARIABLE_COL (?i:(SESSION|GLOBAL|ARGS_POST|ARGS_GET|ARGS|FILES_SIZES|FILES_NAMES|FILES_TMP_CONTENT|MULTIPART_FILENAME|MULTIPART_NAME|MATCHED_VARS_NAMES|MATCHED_VARS|FILES|QUERY_STRING|REQUEST_COOKIES|REQUEST_HEADERS|RESPONSE_HEADERS|GEO|IP|REQUEST_COOKIES_NAMES))
|
||||
|
||||
VARIABLE_TX (?i:TX)
|
||||
VARIABLE_WEBSERVER_ERROR_LOG (?:WEBSERVER_ERROR_LOG)
|
||||
@@ -136,6 +136,7 @@ RUN_TIME_VAR_TIME_MON (?i:TIME_MON)
|
||||
RUN_TIME_VAR_TIME_SEC (?i:TIME_SEC)
|
||||
RUN_TIME_VAR_TIME_WDAY (?i:TIME_WDAY)
|
||||
RUN_TIME_VAR_TIME_YEAR (?i:TIME_YEAR)
|
||||
RUN_TIME_VAR_XML (?i:XML)
|
||||
|
||||
VARIABLENOCOLON (?i:REQBODY_ERROR|MULTIPART_STRICT_ERROR|MULTIPART_UNMATCHED_BOUNDARY|REMOTE_ADDR|REQUEST_LINE)
|
||||
|
||||
@@ -227,6 +228,8 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
|
||||
[!&]?{VARIABLE}(\:[\']{FREE_TEXT_QUOTE}[\'])? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE(yytext, *driver.loc.back()); }
|
||||
[!&]?{VARIABLE_COL}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_COL(yytext, *driver.loc.back()); }
|
||||
[!&]?{VARIABLE_COL}(\:[\']{FREE_TEXT_QUOTE}[\'])? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_COL(yytext, *driver.loc.back()); }
|
||||
[!&]?{RUN_TIME_VAR_XML}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_XML(yytext, *driver.loc.back()); }
|
||||
[!&]?{RUN_TIME_VAR_XML}(\:[\']{FREE_TEXT_QUOTE}[\'])? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_XML(yytext, *driver.loc.back()); }
|
||||
[!&]?{VARIABLE_TX}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_TX(yytext, *driver.loc.back()); }
|
||||
[!&]?{VARIABLE_TX}(\:[\']{FREE_TEXT_QUOTE}[\'])? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_TX(yytext, *driver.loc.back()); }
|
||||
[!&]?{RUN_TIME_VAR_DUR} { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, *driver.loc.back()); }
|
||||
@@ -243,6 +246,8 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
|
||||
["][!&]?{VARIABLE_TX}(\:[\']{FREE_TEXT_QUOTE}[\'])?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_TX(yytext, *driver.loc.back()); }
|
||||
["][!&]?{VARIABLE_COL}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_COL(yytext, *driver.loc.back()); }
|
||||
["][!&]?{VARIABLE_COL}(\:[\']{FREE_TEXT_QUOTE}[\'])?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_VARIABLE_COL(yytext, *driver.loc.back()); }
|
||||
["][!&]?{RUN_TIME_VAR_XML}(\:{DICT_ELEMENT})? { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_XML(yytext, *driver.loc.back()); }
|
||||
["][!&]?{RUN_TIME_VAR_XML}(\:[\']{FREE_TEXT_QUOTE}[\'])?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_XML(yytext, *driver.loc.back()); }
|
||||
|
||||
["][!&]?{RUN_TIME_VAR_DUR}["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_DUR(yytext, *driver.loc.back()); }
|
||||
["][!&]?{RUN_TIME_VAR_ENV}(\:{DICT_ELEMENT})?["] { BEGIN(EXPECTING_OPERATOR); return yy::seclang_parser::make_RUN_TIME_VAR_ENV(yytext, *driver.loc.back()); }
|
||||
|
122
src/request_body_processor/xml.cc
Normal file
122
src/request_body_processor/xml.cc
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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/xml.h"
|
||||
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace modsecurity {
|
||||
namespace RequestBodyProcessor {
|
||||
|
||||
|
||||
XML::XML(Transaction *transaction)
|
||||
: m_transaction(transaction) {
|
||||
m_data.doc = NULL;
|
||||
m_data.parsing_ctx = NULL;
|
||||
m_data.sax_handler = NULL;
|
||||
}
|
||||
|
||||
|
||||
XML::~XML() {
|
||||
if (m_data.doc != NULL) {
|
||||
xmlFreeDoc(m_data.doc);
|
||||
m_data.doc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool XML::init() {
|
||||
// xmlParserInputBufferCreateFilenameFunc entity;
|
||||
// entity = xmlParserInputBufferCreateFilenameDefault(
|
||||
// this->unloadExternalEntity);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool XML::processChunk(const char *buf, unsigned int size) {
|
||||
/* We want to initialise our parsing context here, to
|
||||
* enable us to pass it the first chunk of data so that
|
||||
* it can attempt to auto-detect the encoding.
|
||||
*/
|
||||
if (m_data.parsing_ctx == NULL) {
|
||||
/* First invocation. */
|
||||
|
||||
debug(4, "XML: Initialising parser.");
|
||||
|
||||
/* NOTE When Sax interface is used libxml will not
|
||||
* create the document object, but we need it.
|
||||
|
||||
msr->xml->sax_handler = (xmlSAXHandler *)apr_pcalloc(msr->mp,
|
||||
sizeof(xmlSAXHandler));
|
||||
if (msr->xml->sax_handler == NULL) return -1;
|
||||
msr->xml->sax_handler->error = xml_receive_sax_error;
|
||||
msr->xml->sax_handler->warning = xml_receive_sax_error;
|
||||
msr->xml->parsing_ctx = xmlCreatePushParserCtxt(msr->xml->sax_handler,
|
||||
msr, buf, size, "body.xml");
|
||||
|
||||
*/
|
||||
|
||||
m_data.parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL,
|
||||
buf, size, "body.xml");
|
||||
|
||||
if (m_data.parsing_ctx == NULL) {
|
||||
debug(4, "XML: Failed to create parsing context.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Not a first invocation. */
|
||||
xmlParseChunk(m_data.parsing_ctx, buf, size, 0);
|
||||
if (m_data.parsing_ctx->wellFormed != 1) {
|
||||
debug(4, "XML: Failed parsing document.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool XML::complete() {
|
||||
/* Only if we have a context, meaning we've done some work. */
|
||||
if (m_data.parsing_ctx != NULL) {
|
||||
/* This is how we signalise the end of parsing to libxml. */
|
||||
xmlParseChunk(m_data.parsing_ctx, NULL, 0, 1);
|
||||
|
||||
/* Preserve the results for our reference. */
|
||||
m_data.well_formed = m_data.parsing_ctx->wellFormed;
|
||||
m_data.doc = m_data.parsing_ctx->myDoc;
|
||||
|
||||
/* Clean up everything else. */
|
||||
xmlFreeParserCtxt(m_data.parsing_ctx);
|
||||
m_data.parsing_ctx = NULL;
|
||||
debug(4, "XML: Parsing complete (well_formed " \
|
||||
+ std::to_string(m_data.well_formed) + ").");
|
||||
|
||||
if (m_data.well_formed != 1) {
|
||||
debug(4, "XML: Failed parsing document.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace RequestBodyProcessor
|
||||
} // namespace modsecurity
|
68
src/request_body_processor/xml.h
Normal file
68
src/request_body_processor/xml.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 <libxml/xmlschemas.h>
|
||||
#include <libxml/xpath.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "modsecurity/transaction.h"
|
||||
|
||||
#ifndef SRC_REQUEST_BODY_PROCESSOR_XML_H_
|
||||
#define SRC_REQUEST_BODY_PROCESSOR_XML_H_
|
||||
|
||||
|
||||
namespace modsecurity {
|
||||
namespace RequestBodyProcessor {
|
||||
|
||||
|
||||
struct xml_data {
|
||||
xmlSAXHandler *sax_handler;
|
||||
xmlParserCtxtPtr parsing_ctx;
|
||||
xmlDocPtr doc;
|
||||
|
||||
unsigned int well_formed;
|
||||
};
|
||||
|
||||
typedef struct xml_data xml_data;
|
||||
|
||||
class XML {
|
||||
public:
|
||||
explicit XML(Transaction *transaction);
|
||||
~XML();
|
||||
bool init();
|
||||
bool processChunk(const char *buf, unsigned int size);
|
||||
bool complete();
|
||||
static xmlParserInputBufferPtr unloadExternalEntity(const char *URI,
|
||||
xmlCharEncoding enc) { return NULL; }
|
||||
|
||||
#ifndef NO_LOGS
|
||||
void debug(int a, std::string str) {
|
||||
m_transaction->debug(a, str);
|
||||
}
|
||||
#endif
|
||||
xml_data m_data;
|
||||
|
||||
private:
|
||||
Transaction *m_transaction;
|
||||
std::string m_header;
|
||||
};
|
||||
|
||||
} // namespace RequestBodyProcessor
|
||||
} // namespace modsecurity
|
||||
|
||||
#endif // SRC_REQUEST_BODY_PROCESSOR_XML_H_
|
@@ -37,6 +37,7 @@
|
||||
#include "modsecurity/intervention.h"
|
||||
#include "modsecurity/modsecurity.h"
|
||||
#include "request_body_processor/multipart.h"
|
||||
#include "request_body_processor/xml.h"
|
||||
#include "audit_log/audit_log.h"
|
||||
#include "src/unique_id.h"
|
||||
#include "src/utils.h"
|
||||
@@ -44,6 +45,7 @@
|
||||
|
||||
using modsecurity::actions::Action;
|
||||
using modsecurity::RequestBodyProcessor::Multipart;
|
||||
using modsecurity::RequestBodyProcessor::XML;
|
||||
|
||||
namespace modsecurity {
|
||||
|
||||
@@ -113,7 +115,8 @@ Transaction::Transaction(ModSecurity *ms, Rules *rules, void *logCbData)
|
||||
m_logCbData(logCbData),
|
||||
m_ms(ms),
|
||||
m_collections(ms->m_global_collection, ms->m_ip_collection,
|
||||
ms->m_session_collection, ms->m_user_collection) {
|
||||
ms->m_session_collection, ms->m_user_collection),
|
||||
m_xml(new RequestBodyProcessor::XML(this)) {
|
||||
m_id = std::to_string(this->m_timeStamp) + \
|
||||
std::to_string(generate_transaction_unique_id());
|
||||
m_rules->incrementReferenceCount();
|
||||
@@ -156,6 +159,8 @@ Transaction::~Transaction() {
|
||||
m_rulesMessages.clear();
|
||||
|
||||
m_rules->decrementReferenceCount();
|
||||
|
||||
delete m_xml;
|
||||
}
|
||||
|
||||
|
||||
@@ -478,6 +483,10 @@ int Transaction::addRequestHeader(const std::string& key,
|
||||
if (l == "application/x-www-form-urlencoded") {
|
||||
this->m_requestBodyType = WWWFormUrlEncoded;
|
||||
}
|
||||
|
||||
if (l == "text/xml") {
|
||||
this->m_requestBodyType = XMLRequestBody;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -581,6 +590,18 @@ int Transaction::processRequestBody() {
|
||||
*
|
||||
*/
|
||||
|
||||
if (m_requestBodyType == XMLRequestBody) {
|
||||
std::string *a = m_collections.resolveFirst(
|
||||
"REQUEST_HEADERS:Content-Type");
|
||||
if (a != NULL) {
|
||||
if (m_xml->init() == true) {
|
||||
m_xml->processChunk(m_requestBody.str().c_str(),
|
||||
m_requestBody.str().size());
|
||||
m_xml->complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_requestBodyType == MultiPartRequestBody) {
|
||||
std::string *a = m_collections.resolveFirst(
|
||||
"REQUEST_HEADERS:Content-Type");
|
||||
|
138
src/variables/xml.cc
Normal file
138
src/variables/xml.cc
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 "variables/xml.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <libxml/xmlschemas.h>
|
||||
#include <libxml/xpath.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
|
||||
#include "modsecurity/transaction.h"
|
||||
|
||||
#include "src/request_body_processor/xml.h"
|
||||
|
||||
namespace modsecurity {
|
||||
namespace Variables {
|
||||
|
||||
void XML::evaluateInternal(Transaction *t,
|
||||
std::vector<const collection::Variable *> *l) {
|
||||
xmlXPathContextPtr xpathCtx;
|
||||
xmlXPathObjectPtr xpathObj;
|
||||
xmlNodeSetPtr nodes;
|
||||
std::string key;
|
||||
std::string param;
|
||||
const xmlChar* xpathExpr = NULL;
|
||||
int i;
|
||||
size_t pos;
|
||||
|
||||
pos = m_name.find_first_of(":");
|
||||
if (pos == std::string::npos) {
|
||||
key = std::string(m_name, 0);
|
||||
param = "";
|
||||
} else {
|
||||
key = std::string(m_name, 0, pos);
|
||||
param = std::string(m_name, pos+1, m_name.length() - (pos + 1));
|
||||
}
|
||||
|
||||
/* Is there an XML document tree at all? */
|
||||
if (t->m_xml->m_data.doc == NULL) {
|
||||
/* Sorry, we've got nothing to give! */
|
||||
return;
|
||||
}
|
||||
if (param.empty() == true) {
|
||||
/* Invocation without an XPath expression makes sense
|
||||
* with functions that manipulate the document tree.
|
||||
*/
|
||||
l->push_back(new collection::Variable("XML",
|
||||
std::string("[XML document tree]" + param)));
|
||||
return;
|
||||
}
|
||||
/* Process the XPath expression. */
|
||||
xpathExpr = (const xmlChar*)param.c_str();
|
||||
xpathCtx = xmlXPathNewContext(t->m_xml->m_data.doc);
|
||||
if (xpathCtx == NULL) {
|
||||
t->debug(1, "XML: Unable to create new XPath context.");
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
/* Look through the actionset of the associated rule
|
||||
* for the namespace information. Register them if any are found.
|
||||
*/
|
||||
tarr = apr_table_elts(rule->actionset->actions);
|
||||
telts = (const apr_table_entry_t*)tarr->elts;
|
||||
for (i = 0; i < tarr->nelts; i++) {
|
||||
msre_action *action = (msre_action *)telts[i].val;
|
||||
|
||||
if (strcasecmp(action->metadata->name, "xmlns") == 0) {
|
||||
char *prefix, *href;
|
||||
|
||||
if (parse_name_eq_value(mptmp, action->param, &prefix, &href) < 0) return -1;
|
||||
if ((prefix == NULL)||(href == NULL)) return -1;
|
||||
|
||||
if(xmlXPathRegisterNs(xpathCtx, (const xmlChar*)prefix, (const xmlChar*)href) != 0) {
|
||||
msr_log(msr, 1, "Failed to register XML namespace href \"%s\" prefix \"%s\".",
|
||||
log_escape(mptmp, prefix), log_escape(mptmp, href));
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr_log(msr, 4, "Registered XML namespace href \"%s\" prefix \"%s\".",
|
||||
log_escape(mptmp, prefix), log_escape(mptmp, href));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialise XPath expression. */
|
||||
xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
|
||||
if (xpathObj == NULL) {
|
||||
t->debug(1, "XML: Unable to evaluate xpath expression.");
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
return;
|
||||
}
|
||||
/* Evaluate XPath expression. */
|
||||
nodes = xpathObj->nodesetval;
|
||||
if (nodes == NULL) {
|
||||
xmlXPathFreeObject(xpathObj);
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
return;
|
||||
}
|
||||
/* Create one variable for each node in the result. */
|
||||
for (i = 0; i < nodes->nodeNr; i++) {
|
||||
char *content = NULL;
|
||||
content = reinterpret_cast<char *>(
|
||||
xmlNodeGetContent(nodes->nodeTab[i]));
|
||||
if (content != NULL) {
|
||||
l->push_back(new collection::Variable(m_name,
|
||||
std::string(content)));
|
||||
xmlFree(content);
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(xpathObj);
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Variables
|
||||
} // namespace modsecurity
|
45
src/variables/xml.h
Normal file
45
src/variables/xml.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
|
||||
#ifndef SRC_VARIABLES_XML_H_
|
||||
#define SRC_VARIABLES_XML_H_
|
||||
|
||||
#include "variables/variable.h"
|
||||
#include "src/variables/xml.h"
|
||||
|
||||
namespace modsecurity {
|
||||
|
||||
class Transaction;
|
||||
namespace Variables {
|
||||
|
||||
class XML : public Variable {
|
||||
public:
|
||||
explicit XML(std::string _name)
|
||||
: Variable(_name) { }
|
||||
|
||||
void evaluateInternal(Transaction *transaction,
|
||||
std::vector<const collection::Variable *> *l) override;
|
||||
};
|
||||
|
||||
} // namespace Variables
|
||||
} // namespace modsecurity
|
||||
|
||||
#endif // SRC_VARIABLES_XML_H_
|
Reference in New Issue
Block a user