MXS-3021: Make strictness of dbfwfilter configurable
In some cases the dbfwfilter is too strict and SQL that would not match a rule is blocked due to it not being fully parsed. To allow a more lenient mode of operation, the requirement for full parsing must be made configurable.
This commit is contained in:
@ -113,31 +113,46 @@ Log all queries that do not match a rule. The matched user and the query is
|
|||||||
logged. The log messages are logged at the notice level.
|
logged. The log messages are logged at the notice level.
|
||||||
|
|
||||||
#### `treat_string_as_field`
|
#### `treat_string_as_field`
|
||||||
|
|
||||||
This optional parameter specifies how the database firewall should treat
|
This optional parameter specifies how the database firewall should treat
|
||||||
strings. If true, they will be handled as fields, which will cause column
|
strings. If true, they will be handled as fields, which will cause column
|
||||||
blocking rules to match even if `ANSI_QUOTES` has been enabled and `"` is
|
blocking rules to match even if `ANSI_QUOTES` has been enabled and `"` is
|
||||||
used instead of backtick.
|
used instead of backtick.
|
||||||
|
|
||||||
```
|
```
|
||||||
treat_string_as_field=false
|
treat_string_as_field=false
|
||||||
```
|
```
|
||||||
|
|
||||||
The default value is `true`.
|
The default value is `true`.
|
||||||
|
|
||||||
Note that this may cause a false positive, if a "true" string contains the
|
Note that this may cause a false positive, if a "true" string contains the
|
||||||
name of a column to be blocked.
|
name of a column to be blocked.
|
||||||
|
|
||||||
#### `treat_string_arg_as_field`
|
#### `treat_string_arg_as_field`
|
||||||
|
|
||||||
This optional parameter specifies how the database firewall should treat
|
This optional parameter specifies how the database firewall should treat
|
||||||
strings used as arguments to functions. If true, they will be handled
|
strings used as arguments to functions. If true, they will be handled
|
||||||
as fields, which will cause function column blocking rules to match even
|
as fields, which will cause function column blocking rules to match even
|
||||||
even if `ANSI_QUOTES` has been enabled and `"` is used instead of backtick.
|
even if `ANSI_QUOTES` has been enabled and `"` is used instead of backtick.
|
||||||
|
|
||||||
```
|
```
|
||||||
treat_string_arg_as_field=false
|
treat_string_arg_as_field=false
|
||||||
```
|
```
|
||||||
|
|
||||||
The default value is `true`.
|
The default value is `true`.
|
||||||
|
|
||||||
Note that this may cause a false positive, if a "true" string contains the
|
Note that this may cause a false positive, if a "true" string contains the
|
||||||
name of a column to be blocked.
|
name of a column to be blocked.
|
||||||
|
|
||||||
|
#### `strict`
|
||||||
|
|
||||||
|
Whether to treat unsupported SQL or multi-statement SQL as an error. This is a
|
||||||
|
boolean parameter and the default value is `true`.
|
||||||
|
|
||||||
|
When disabled, SQL that cannot be fully parsed is allowed to pass if the rules
|
||||||
|
do not cause it to be blocked. This can be used to provide a best-effort mode
|
||||||
|
where uncertainly about the SQL is allowed.
|
||||||
|
|
||||||
## Rule syntax
|
## Rule syntax
|
||||||
|
|
||||||
The rules are defined by using the following syntax:
|
The rules are defined by using the following syntax:
|
||||||
|
|||||||
@ -635,6 +635,11 @@ MXS_MODULE* MXS_CREATE_MODULE()
|
|||||||
MXS_MODULE_PARAM_BOOL,
|
MXS_MODULE_PARAM_BOOL,
|
||||||
"true"
|
"true"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"strict",
|
||||||
|
MXS_MODULE_PARAM_BOOL,
|
||||||
|
"true"
|
||||||
|
},
|
||||||
{MXS_END_MODULE_PARAMS}
|
{MXS_END_MODULE_PARAMS}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1254,6 +1259,7 @@ Dbfw::Dbfw(MXS_CONFIG_PARAMETER* params)
|
|||||||
, m_treat_string_arg_as_field(params->get_bool("treat_string_arg_as_field"))
|
, m_treat_string_arg_as_field(params->get_bool("treat_string_arg_as_field"))
|
||||||
, m_filename(params->get_string("rules"))
|
, m_filename(params->get_string("rules"))
|
||||||
, m_version(atomic_add(&global_version, 1))
|
, m_version(atomic_add(&global_version, 1))
|
||||||
|
, m_strict(params->get_bool("strict"))
|
||||||
{
|
{
|
||||||
if (params->get_bool("log_match"))
|
if (params->get_bool("log_match"))
|
||||||
{
|
{
|
||||||
@ -1533,7 +1539,7 @@ int DbfwSession::routeQuery(GWBUF* buffer)
|
|||||||
type = qc_get_type_mask(buffer);
|
type = qc_get_type_mask(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modutil_is_SQL(buffer) && modutil_count_statements(buffer) > 1)
|
if (m_instance->strict() && modutil_is_SQL(buffer) && modutil_count_statements(buffer) > 1)
|
||||||
{
|
{
|
||||||
set_error("This filter does not support multi-statements.");
|
set_error("This filter does not support multi-statements.");
|
||||||
rval = send_error();
|
rval = send_error();
|
||||||
@ -1810,13 +1816,16 @@ bool rule_matches(Dbfw* my_instance,
|
|||||||
{
|
{
|
||||||
qc_parse_result_t parse_result = qc_parse(queue, QC_COLLECT_ALL);
|
qc_parse_result_t parse_result = qc_parse(queue, QC_COLLECT_ALL);
|
||||||
|
|
||||||
if (parse_result == QC_QUERY_INVALID)
|
if (my_instance->strict())
|
||||||
{
|
{
|
||||||
msg = create_parse_error(my_instance, "tokenized", query, &matches);
|
if (parse_result == QC_QUERY_INVALID)
|
||||||
}
|
{
|
||||||
else if (parse_result != QC_QUERY_PARSED && rule->need_full_parsing(queue))
|
msg = create_parse_error(my_instance, "tokenized", query, &matches);
|
||||||
{
|
}
|
||||||
msg = create_parse_error(my_instance, "parsed completely", query, &matches);
|
else if (parse_result != QC_QUERY_PARSED && rule->need_full_parsing(queue))
|
||||||
|
{
|
||||||
|
msg = create_parse_error(my_instance, "parsed completely", query, &matches);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -244,6 +244,16 @@ public:
|
|||||||
return m_treat_string_arg_as_field;
|
return m_treat_string_arg_as_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether unsupported SQL is an error
|
||||||
|
*
|
||||||
|
* @return True if unsupported SQL is an error
|
||||||
|
*/
|
||||||
|
bool strict() const
|
||||||
|
{
|
||||||
|
return m_strict;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get logging option bitmask
|
* Get logging option bitmask
|
||||||
*
|
*
|
||||||
@ -292,6 +302,7 @@ private:
|
|||||||
mutable std::mutex m_lock; /*< Instance spinlock */
|
mutable std::mutex m_lock; /*< Instance spinlock */
|
||||||
std::string m_filename; /*< Path to the rule file */
|
std::string m_filename; /*< Path to the rule file */
|
||||||
int m_version; /*< Latest rule file version, incremented on reload */
|
int m_version; /*< Latest rule file version, incremented on reload */
|
||||||
|
bool m_strict;
|
||||||
|
|
||||||
Dbfw(MXS_CONFIG_PARAMETER* param);
|
Dbfw(MXS_CONFIG_PARAMETER* param);
|
||||||
bool do_reload_rules(std::string filename);
|
bool do_reload_rules(std::string filename);
|
||||||
|
|||||||
Reference in New Issue
Block a user