MXS-2457 Treat string args as fields

The masking filter will now consider all string arguments to
functions to be fields. This in order to prevent bypassing of
the masking with

    > set @@sql_mode='ANSI_QUOTES';
    > select concat("ssn") from masking;

This may lead to false positives, but no can do.
This commit is contained in:
Johan Wikman
2019-05-02 14:16:30 +03:00
parent f09d46c8e6
commit 3a5a8b13b9
5 changed files with 119 additions and 9 deletions

View File

@ -145,6 +145,12 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
Config::require_fully_parsed_default,
MXS_MODULE_OPT_NONE,
},
{
Config::treat_string_arg_as_field_name,
MXS_MODULE_PARAM_BOOL,
Config::treat_string_arg_as_field_default,
MXS_MODULE_OPT_NONE
},
{MXS_END_MODULE_PARAMS}
}
};

View File

@ -17,14 +17,15 @@
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_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_warn_type_mismatch[] = "warn_type_mismatch";
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_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_name_treat_string_arg_as_field[] = "treat_string_arg_as_field";
const char config_value_abort[] = "abort";
@ -105,7 +106,11 @@ const char* MaskingFilterConfig::check_subqueries_default = config_value_true;
const char* MaskingFilterConfig::require_fully_parsed_name = config_name_require_fully_parsed;
const char* MaskingFilterConfig::require_fully_parsed_default = config_name_require_fully_parsed;
/*
* PARAM treat_string_arg_as_field
*/
const char* MaskingFilterConfig::treat_string_arg_as_field_name = config_name_treat_string_arg_as_field;
const char* MaskingFilterConfig::treat_string_arg_as_field_default = config_value_true;
/*
* MaskingFilterConfig
*/
@ -161,3 +166,9 @@ bool MaskingFilterConfig::get_require_fully_parsed(const MXS_CONFIG_PARAMETER* p
{
return config_get_bool(pParams, require_fully_parsed_name);
}
// static
bool MaskingFilterConfig::get_treat_string_arg_as_field(const MXS_CONFIG_PARAMETER* pParams)
{
return config_get_bool(pParams, treat_string_arg_as_field_name);
}

View File

@ -57,6 +57,9 @@ public:
static const char* require_fully_parsed_name;
static const char* require_fully_parsed_default;
static const char* treat_string_arg_as_field_name;
static const char* treat_string_arg_as_field_default;
MaskingFilterConfig(const char* zName, const MXS_CONFIG_PARAMETER* pParams)
: m_name(zName)
, m_large_payload(get_large_payload(pParams))
@ -67,6 +70,7 @@ public:
, m_check_unions(get_check_unions(pParams))
, m_check_subqueries(get_check_subqueries(pParams))
, m_require_fully_parsed(get_require_fully_parsed(pParams))
, m_treat_string_arg_as_field(get_treat_string_arg_as_field(pParams))
{
}
@ -119,6 +123,11 @@ public:
return m_require_fully_parsed;
}
bool treat_string_arg_as_field() const
{
return m_treat_string_arg_as_field;
}
void set_large_payload(large_payload_t l)
{
m_large_payload = l;
@ -158,6 +167,11 @@ public:
m_require_fully_parsed = b;
}
void set_treat_string_arg_as_field(bool b)
{
m_treat_string_arg_as_field = b;
}
bool is_parsing_needed() const
{
return prevent_function_usage() || check_user_variables() || check_unions() || check_subqueries();
@ -171,6 +185,7 @@ public:
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);
static bool get_treat_string_arg_as_field(const MXS_CONFIG_PARAMETER* pParams);
private:
std::string m_name;
@ -182,4 +197,5 @@ private:
bool m_check_unions;
bool m_check_subqueries;
bool m_require_fully_parsed;
bool m_treat_string_arg_as_field;
};

View File

@ -48,6 +48,46 @@ GWBUF* create_parse_error_response()
return create_error_response(zMessage);
}
class EnableOption
{
public:
EnableOption(const EnableOption&) = delete;
EnableOption& operator=(const EnableOption&) = delete;
EnableOption(uint32_t option)
: m_option(option)
, m_options(0)
, m_disable(false)
{
if (m_option)
{
m_options = qc_get_options();
if (!(m_options & m_option))
{
uint32_t options = (m_options | m_option);
MXB_AT_DEBUG(bool rv = )qc_set_options(options);
mxb_assert(rv);
m_disable = true;
}
}
}
~EnableOption()
{
if (m_disable)
{
MXB_AT_DEBUG(bool rv = )qc_set_options(m_options);
mxb_assert(rv);
}
}
private:
uint32_t m_option;
uint32_t m_options;
bool m_disable;
};
}
MaskingFilterSession::MaskingFilterSession(MXS_SESSION* pSession, const MaskingFilter* pFilter)
@ -127,6 +167,9 @@ bool MaskingFilterSession::check_textual_query(GWBUF* pPacket)
{
bool rv = false;
uint32_t option = m_filter.config().treat_string_arg_as_field() ? QC_OPTION_STRING_ARG_AS_FIELD : 0;
EnableOption enable(option);
if (qc_parse(pPacket, QC_COLLECT_FIELDS | QC_COLLECT_FUNCTIONS) == QC_QUERY_PARSED
|| !m_filter.config().require_fully_parsed())
{
@ -166,6 +209,9 @@ bool MaskingFilterSession::check_binary_query(GWBUF* pPacket)
{
bool rv = false;
uint32_t option = m_filter.config().treat_string_arg_as_field() ? QC_OPTION_STRING_ARG_AS_FIELD : 0;
EnableOption enable(option);
if (qc_parse(pPacket, QC_COLLECT_FIELDS | QC_COLLECT_FUNCTIONS) == QC_QUERY_PARSED
|| !m_filter.config().require_fully_parsed())
{