MXS-2393 Add parameter 'require_fully_parsed'
If set to true and if any of the other blocking related parameters is true, then a statement that cannot be fully parsed will be blocked. Default is true.
This commit is contained in:
@ -87,6 +87,15 @@ SELECT revealed_ssn FROM cheat;
|
|||||||
```
|
```
|
||||||
to get access to the cleartext version of a masked field `ssn`.
|
to get access to the cleartext version of a masked field `ssn`.
|
||||||
|
|
||||||
|
From MaxScale 2.3.5 onwards, the masking filter will, if any of the
|
||||||
|
`prevent_function_usage`, `check_user_variables`, `check_unions` or
|
||||||
|
`check_subqueries` parameters is set to true, block statements that
|
||||||
|
cannot be fully parsed.
|
||||||
|
|
||||||
|
Please see the configuration parameter
|
||||||
|
[require_fully_parsed](#require_fully_parsed)
|
||||||
|
for how to change the default behaviour.
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
The masking filter can _only_ be used for masking columns of the following
|
The masking filter can _only_ be used for masking columns of the following
|
||||||
@ -186,6 +195,26 @@ prevent_function_usage=false
|
|||||||
```
|
```
|
||||||
The default value is `true`.
|
The default value is `true`.
|
||||||
|
|
||||||
|
#### `require_fully_parsed`
|
||||||
|
|
||||||
|
This optional parameter specifies how the masking filter should
|
||||||
|
behave in case any of `prevent_function_usage`, `check_user_variables`,
|
||||||
|
`check_unions` or `check_subqueries` is true and it encounters a
|
||||||
|
statement that cannot be fully parsed,
|
||||||
|
|
||||||
|
If true, then statements that cannot be fully parsed (due to a
|
||||||
|
parser limitation) will be blocked.
|
||||||
|
```
|
||||||
|
require_fully_parsed=false
|
||||||
|
```
|
||||||
|
|
||||||
|
The default value is `true`.
|
||||||
|
|
||||||
|
Note that if this parameter is set to false, then `prevent_function_usage`,
|
||||||
|
`check_user_variables`, `check_unions` and `check_subqueries` are rendered
|
||||||
|
less effective, as it with a statement that can not be fully parsed may be
|
||||||
|
possible to bypass the protection that they are intended to provide.
|
||||||
|
|
||||||
#### `check_user_variables`
|
#### `check_user_variables`
|
||||||
|
|
||||||
This optional parameter specifies how the masking filter should
|
This optional parameter specifies how the masking filter should
|
||||||
|
@ -139,6 +139,12 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
|||||||
Config::check_subqueries_default,
|
Config::check_subqueries_default,
|
||||||
MXS_MODULE_OPT_NONE,
|
MXS_MODULE_OPT_NONE,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Config::require_fully_parsed_name,
|
||||||
|
MXS_MODULE_PARAM_BOOL,
|
||||||
|
Config::require_fully_parsed_default,
|
||||||
|
MXS_MODULE_OPT_NONE,
|
||||||
|
},
|
||||||
{MXS_END_MODULE_PARAMS}
|
{MXS_END_MODULE_PARAMS}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -17,21 +17,23 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const char config_name_check_subqueries[] = "check_subqueries";
|
||||||
|
const char config_name_check_unions[] = "check_unions";
|
||||||
|
const char config_name_check_user_variables[] = "check_user_variables";
|
||||||
const char config_name_large_payload[] = "large_payload";
|
const char config_name_large_payload[] = "large_payload";
|
||||||
|
const char config_name_prevent_function_usage[] = "prevent_function_usage";
|
||||||
|
const char config_name_require_fully_parsed[] = "require_fully_parsed";
|
||||||
const char config_name_rules[] = "rules";
|
const char config_name_rules[] = "rules";
|
||||||
const char config_name_warn_type_mismatch[] = "warn_type_mismatch";
|
const char config_name_warn_type_mismatch[] = "warn_type_mismatch";
|
||||||
|
|
||||||
|
|
||||||
const char config_value_abort[] = "abort";
|
const char config_value_abort[] = "abort";
|
||||||
|
const char config_value_always[] = "always";
|
||||||
const char config_value_ignore[] = "ignore";
|
const char config_value_ignore[] = "ignore";
|
||||||
const char config_value_never[] = "never";
|
const char config_value_never[] = "never";
|
||||||
const char config_value_always[] = "always";
|
|
||||||
|
|
||||||
const char config_name_prevent_function_usage[] = "prevent_function_usage";
|
|
||||||
const char config_check_user_variables[] = "check_user_variables";
|
|
||||||
const char config_check_unions[] = "check_unions";
|
|
||||||
const char config_check_subqueries[] = "check_subqueries";
|
|
||||||
|
|
||||||
const char config_value_true[] = "true";
|
const char config_value_true[] = "true";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -63,10 +65,9 @@ const char* MaskingFilterConfig::rules_name = config_name_rules;
|
|||||||
* PARAM warn_type_mismatch
|
* PARAM warn_type_mismatch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// static
|
|
||||||
const char* MaskingFilterConfig::warn_type_mismatch_name = config_name_warn_type_mismatch;
|
const char* MaskingFilterConfig::warn_type_mismatch_name = config_name_warn_type_mismatch;
|
||||||
|
const char* MaskingFilterConfig::warn_type_mismatch_default = config_value_never;
|
||||||
|
|
||||||
// static
|
|
||||||
const MXS_ENUM_VALUE MaskingFilterConfig::warn_type_mismatch_values[] =
|
const MXS_ENUM_VALUE MaskingFilterConfig::warn_type_mismatch_values[] =
|
||||||
{
|
{
|
||||||
{config_value_never, MaskingFilterConfig::WARN_NEVER },
|
{config_value_never, MaskingFilterConfig::WARN_NEVER },
|
||||||
@ -74,46 +75,36 @@ const MXS_ENUM_VALUE MaskingFilterConfig::warn_type_mismatch_values[] =
|
|||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
// static
|
|
||||||
const char* MaskingFilterConfig::warn_type_mismatch_default = config_value_never;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PARAM prevent_function_usage
|
* PARAM prevent_function_usage
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// static
|
|
||||||
const char* MaskingFilterConfig::prevent_function_usage_name = config_name_prevent_function_usage;
|
const char* MaskingFilterConfig::prevent_function_usage_name = config_name_prevent_function_usage;
|
||||||
|
|
||||||
// static
|
|
||||||
const char* MaskingFilterConfig::prevent_function_usage_default = config_value_true;
|
const char* MaskingFilterConfig::prevent_function_usage_default = config_value_true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PARAM check_user_variables
|
* PARAM check_user_variables
|
||||||
*/
|
*/
|
||||||
// static
|
const char* MaskingFilterConfig::check_user_variables_name = config_name_check_user_variables;
|
||||||
const char* MaskingFilterConfig::check_user_variables_name = config_check_user_variables;
|
|
||||||
|
|
||||||
// static
|
|
||||||
const char* MaskingFilterConfig::check_user_variables_default = config_value_true;
|
const char* MaskingFilterConfig::check_user_variables_default = config_value_true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PARAM check_unions
|
* PARAM check_unions
|
||||||
*/
|
*/
|
||||||
// static
|
const char* MaskingFilterConfig::check_unions_name = config_name_check_unions;
|
||||||
const char* MaskingFilterConfig::check_unions_name = config_check_unions;
|
|
||||||
|
|
||||||
// static
|
|
||||||
const char* MaskingFilterConfig::check_unions_default = config_value_true;
|
const char* MaskingFilterConfig::check_unions_default = config_value_true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PARAM check_subqueries
|
* PARAM check_subqueries
|
||||||
*/
|
*/
|
||||||
// static
|
const char* MaskingFilterConfig::check_subqueries_name = config_name_check_subqueries;
|
||||||
const char* MaskingFilterConfig::check_subqueries_name = config_check_subqueries;
|
|
||||||
|
|
||||||
// static
|
|
||||||
const char* MaskingFilterConfig::check_subqueries_default = config_value_true;
|
const char* MaskingFilterConfig::check_subqueries_default = config_value_true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PARAM require_fully_parsed
|
||||||
|
*/
|
||||||
|
const char* MaskingFilterConfig::require_fully_parsed_name = config_name_require_fully_parsed;
|
||||||
|
const char* MaskingFilterConfig::require_fully_parsed_default = config_name_require_fully_parsed;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MaskingFilterConfig
|
* MaskingFilterConfig
|
||||||
@ -164,3 +155,9 @@ bool MaskingFilterConfig::get_check_subqueries(const MXS_CONFIG_PARAMETER* pPara
|
|||||||
{
|
{
|
||||||
return config_get_bool(pParams, check_subqueries_name);
|
return config_get_bool(pParams, check_subqueries_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool MaskingFilterConfig::get_require_fully_parsed(const MXS_CONFIG_PARAMETER* pParams)
|
||||||
|
{
|
||||||
|
return config_get_bool(pParams, require_fully_parsed_name);
|
||||||
|
}
|
||||||
|
@ -54,6 +54,9 @@ public:
|
|||||||
static const char* check_subqueries_name;
|
static const char* check_subqueries_name;
|
||||||
static const char* check_subqueries_default;
|
static const char* check_subqueries_default;
|
||||||
|
|
||||||
|
static const char* require_fully_parsed_name;
|
||||||
|
static const char* require_fully_parsed_default;
|
||||||
|
|
||||||
MaskingFilterConfig(const char* zName, const MXS_CONFIG_PARAMETER* pParams)
|
MaskingFilterConfig(const char* zName, const MXS_CONFIG_PARAMETER* pParams)
|
||||||
: m_name(zName)
|
: m_name(zName)
|
||||||
, m_large_payload(get_large_payload(pParams))
|
, m_large_payload(get_large_payload(pParams))
|
||||||
@ -63,6 +66,7 @@ public:
|
|||||||
, m_check_user_variables(get_check_user_variables(pParams))
|
, m_check_user_variables(get_check_user_variables(pParams))
|
||||||
, m_check_unions(get_check_unions(pParams))
|
, m_check_unions(get_check_unions(pParams))
|
||||||
, m_check_subqueries(get_check_subqueries(pParams))
|
, m_check_subqueries(get_check_subqueries(pParams))
|
||||||
|
, m_require_fully_parsed(get_require_fully_parsed(pParams))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +114,11 @@ public:
|
|||||||
return m_check_subqueries;
|
return m_check_subqueries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool require_fully_parsed() const
|
||||||
|
{
|
||||||
|
return m_require_fully_parsed;
|
||||||
|
}
|
||||||
|
|
||||||
void set_large_payload(large_payload_t l)
|
void set_large_payload(large_payload_t l)
|
||||||
{
|
{
|
||||||
m_large_payload = l;
|
m_large_payload = l;
|
||||||
@ -144,6 +153,11 @@ public:
|
|||||||
m_check_subqueries = b;
|
m_check_subqueries = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_require_fully_parsed(bool b)
|
||||||
|
{
|
||||||
|
m_require_fully_parsed = b;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_parsing_needed() const
|
bool is_parsing_needed() const
|
||||||
{
|
{
|
||||||
return prevent_function_usage() || check_user_variables() || check_unions() || check_subqueries();
|
return prevent_function_usage() || check_user_variables() || check_unions() || check_subqueries();
|
||||||
@ -156,6 +170,7 @@ public:
|
|||||||
static bool get_check_user_variables(const MXS_CONFIG_PARAMETER* pParams);
|
static bool get_check_user_variables(const MXS_CONFIG_PARAMETER* pParams);
|
||||||
static bool get_check_unions(const MXS_CONFIG_PARAMETER* pParams);
|
static bool get_check_unions(const MXS_CONFIG_PARAMETER* pParams);
|
||||||
static bool get_check_subqueries(const MXS_CONFIG_PARAMETER* pParams);
|
static bool get_check_subqueries(const MXS_CONFIG_PARAMETER* pParams);
|
||||||
|
static bool get_require_fully_parsed(const MXS_CONFIG_PARAMETER* pParams);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
@ -166,4 +181,5 @@ private:
|
|||||||
bool m_check_user_variables;
|
bool m_check_user_variables;
|
||||||
bool m_check_unions;
|
bool m_check_unions;
|
||||||
bool m_check_subqueries;
|
bool m_check_subqueries;
|
||||||
|
bool m_require_fully_parsed;
|
||||||
};
|
};
|
||||||
|
@ -127,7 +127,8 @@ bool MaskingFilterSession::check_textual_query(GWBUF* pPacket)
|
|||||||
{
|
{
|
||||||
bool rv = false;
|
bool rv = false;
|
||||||
|
|
||||||
if (qc_parse(pPacket, QC_COLLECT_FIELDS | QC_COLLECT_FUNCTIONS) == QC_QUERY_PARSED)
|
if (qc_parse(pPacket, QC_COLLECT_FIELDS | QC_COLLECT_FUNCTIONS) == QC_QUERY_PARSED
|
||||||
|
|| !m_filter.config().require_fully_parsed())
|
||||||
{
|
{
|
||||||
if (qc_query_is_type(qc_get_type_mask(pPacket), QUERY_TYPE_PREPARE_NAMED_STMT))
|
if (qc_query_is_type(qc_get_type_mask(pPacket), QUERY_TYPE_PREPARE_NAMED_STMT))
|
||||||
{
|
{
|
||||||
@ -165,7 +166,8 @@ bool MaskingFilterSession::check_binary_query(GWBUF* pPacket)
|
|||||||
{
|
{
|
||||||
bool rv = false;
|
bool rv = false;
|
||||||
|
|
||||||
if (qc_parse(pPacket, QC_COLLECT_FIELDS | QC_COLLECT_FUNCTIONS) == QC_QUERY_PARSED)
|
if (qc_parse(pPacket, QC_COLLECT_FIELDS | QC_COLLECT_FUNCTIONS) == QC_QUERY_PARSED
|
||||||
|
|| !m_filter.config().require_fully_parsed())
|
||||||
{
|
{
|
||||||
rv = check_query(pPacket);
|
rv = check_query(pPacket);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user