From 5346b24fa40fe49d6e27067604dc5f594d1c6eda Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Mon, 1 Apr 2019 09:57:40 +0300 Subject: [PATCH] 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. --- Documentation/Filters/Masking.md | 29 +++++++++ .../modules/filter/masking/maskingfilter.cc | 6 ++ .../filter/masking/maskingfilterconfig.cc | 63 +++++++++---------- .../filter/masking/maskingfilterconfig.hh | 16 +++++ .../filter/masking/maskingfiltersession.cc | 6 +- 5 files changed, 85 insertions(+), 35 deletions(-) diff --git a/Documentation/Filters/Masking.md b/Documentation/Filters/Masking.md index c055b696a..05a763015 100644 --- a/Documentation/Filters/Masking.md +++ b/Documentation/Filters/Masking.md @@ -87,6 +87,15 @@ SELECT revealed_ssn FROM cheat; ``` 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 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`. +#### `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` This optional parameter specifies how the masking filter should diff --git a/server/modules/filter/masking/maskingfilter.cc b/server/modules/filter/masking/maskingfilter.cc index 5a3eb5be2..e33d55ebc 100644 --- a/server/modules/filter/masking/maskingfilter.cc +++ b/server/modules/filter/masking/maskingfilter.cc @@ -139,6 +139,12 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE() Config::check_subqueries_default, 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} } }; diff --git a/server/modules/filter/masking/maskingfilterconfig.cc b/server/modules/filter/masking/maskingfilterconfig.cc index 3f6f2b81c..eab0ed540 100644 --- a/server/modules/filter/masking/maskingfilterconfig.cc +++ b/server/modules/filter/masking/maskingfilterconfig.cc @@ -17,21 +17,23 @@ namespace { -const char config_name_large_payload[] = "large_payload"; -const char config_name_rules[] = "rules"; -const char config_name_warn_type_mismatch[] = "warn_type_mismatch"; - -const char config_value_abort[] = "abort"; -const char config_value_ignore[] = "ignore"; -const char config_value_never[] = "never"; -const char config_value_always[] = "always"; - +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_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_name_require_fully_parsed[] = "require_fully_parsed"; +const char config_name_rules[] = "rules"; +const char config_name_warn_type_mismatch[] = "warn_type_mismatch"; + + +const char config_value_abort[] = "abort"; +const char config_value_always[] = "always"; +const char config_value_ignore[] = "ignore"; +const char config_value_never[] = "never"; const char config_value_true[] = "true"; + } /* @@ -63,10 +65,9 @@ const char* MaskingFilterConfig::rules_name = config_name_rules; * PARAM warn_type_mismatch */ -// static 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[] = { {config_value_never, MaskingFilterConfig::WARN_NEVER }, @@ -74,46 +75,36 @@ const MXS_ENUM_VALUE MaskingFilterConfig::warn_type_mismatch_values[] = {NULL} }; -// static -const char* MaskingFilterConfig::warn_type_mismatch_default = config_value_never; - /* * PARAM prevent_function_usage */ - -// static const char* MaskingFilterConfig::prevent_function_usage_name = config_name_prevent_function_usage; - -// static const char* MaskingFilterConfig::prevent_function_usage_default = config_value_true; /* * PARAM check_user_variables */ -// static -const char* MaskingFilterConfig::check_user_variables_name = config_check_user_variables; - -// static +const char* MaskingFilterConfig::check_user_variables_name = config_name_check_user_variables; const char* MaskingFilterConfig::check_user_variables_default = config_value_true; /* * PARAM check_unions */ -// static -const char* MaskingFilterConfig::check_unions_name = config_check_unions; - -// static +const char* MaskingFilterConfig::check_unions_name = config_name_check_unions; const char* MaskingFilterConfig::check_unions_default = config_value_true; /* * PARAM check_subqueries */ -// static -const char* MaskingFilterConfig::check_subqueries_name = config_check_subqueries; - -// static +const char* MaskingFilterConfig::check_subqueries_name = config_name_check_subqueries; 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 @@ -164,3 +155,9 @@ bool MaskingFilterConfig::get_check_subqueries(const MXS_CONFIG_PARAMETER* pPara { 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); +} diff --git a/server/modules/filter/masking/maskingfilterconfig.hh b/server/modules/filter/masking/maskingfilterconfig.hh index 20c3bb3a7..9b4cb6f37 100644 --- a/server/modules/filter/masking/maskingfilterconfig.hh +++ b/server/modules/filter/masking/maskingfilterconfig.hh @@ -54,6 +54,9 @@ public: static const char* check_subqueries_name; 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) : m_name(zName) , m_large_payload(get_large_payload(pParams)) @@ -63,6 +66,7 @@ public: , m_check_user_variables(get_check_user_variables(pParams)) , m_check_unions(get_check_unions(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; } + bool require_fully_parsed() const + { + return m_require_fully_parsed; + } + void set_large_payload(large_payload_t l) { m_large_payload = l; @@ -144,6 +153,11 @@ public: m_check_subqueries = b; } + void set_require_fully_parsed(bool b) + { + m_require_fully_parsed = b; + } + bool is_parsing_needed() const { 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_unions(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: std::string m_name; @@ -166,4 +181,5 @@ private: bool m_check_user_variables; bool m_check_unions; bool m_check_subqueries; + bool m_require_fully_parsed; }; diff --git a/server/modules/filter/masking/maskingfiltersession.cc b/server/modules/filter/masking/maskingfiltersession.cc index db29f53e8..b9614f046 100644 --- a/server/modules/filter/masking/maskingfiltersession.cc +++ b/server/modules/filter/masking/maskingfiltersession.cc @@ -127,7 +127,8 @@ bool MaskingFilterSession::check_textual_query(GWBUF* pPacket) { 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)) { @@ -165,7 +166,8 @@ bool MaskingFilterSession::check_binary_query(GWBUF* pPacket) { 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); }