未末未未未未末 發表於 2025-8-18 09:22:00

MySQL 密码防暴力破解插件:Connection Control

<p data-tool="mdnice编辑器"><span>Connection Control 是 MySQL 8.0 引入的一个安全功能插件,后移植到 MySQL 5.7.17 和 5.6.35 版本。</span></p>
<p data-tool="mdnice编辑器"><span>其核心功能是:当客户端因账号或密码错误连续多次登录失败时,服务端会对该客户端的后续请求进行延迟处理,且失败次数越多,延迟时间越长。这一机制能显著增加密码被暴力破解的耗时,从而有效遏制此类攻击。</span></p>
<p data-tool="mdnice编辑器"><span>适用场景:</span></p>
<ul class="list-paddingleft-1">
<li><span>面向公网开放的 MySQL 服务器。</span></li>
<li><span>合规性与安全性要求较高的环境。</span></li>
</ul>
<h1 data-tool="mdnice编辑器"><span style="color: rgba(0, 128, 0, 1)">插件效果</span></h1>
<p data-tool="mdnice编辑器"><span>首先我们看看该插件的效果。</span></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code># time mysql -h10.0.0.108 -uroot -p123<span><br><span>ERROR 1045 (28000): Access denied for user 'root'@'10.0.0.75' (using password: YES)<span><br><span>real &nbsp; &nbsp;0m0.013s<span><br><span><br># time mysql -h10.0.0.108 -uroot -p123<span><br><span>ERROR 1045 (28000): Access denied for user 'root'@'10.0.0.75' (using password: YES)<span><br><span>real &nbsp; &nbsp;0m0.013s<span><br><span><br># time mysql -h10.0.0.108 -uroot -p123<span><br><span>ERROR 1045 (28000): Access denied for user 'root'@'10.0.0.75' (using password: YES)<span><br><span>real &nbsp; &nbsp;0m0.013s<span><br><span><br># time mysql -h10.0.0.108 -uroot -p123<span><br><span>ERROR 1045 (28000): Access denied for user 'root'@'10.0.0.75' (using password: YES)<span><br><span>real &nbsp; &nbsp;0m1.013s<span><br><span><br># time mysql -h10.0.0.108 -uroot -p123<span><br><span>ERROR 1045 (28000): Access denied for user 'root'@'10.0.0.75' (using password: YES)<span><br><span>real &nbsp; &nbsp;0m2.013s<span><br><span><br># time mysql -h10.0.0.108 -uroot -p123<span><br><span>ERROR 1045 (28000): Access denied for user 'root'@'10.0.0.75' (using password: YES)<span><br><span>real &nbsp; &nbsp;0m3.014s<span><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></pre>
<p data-tool="mdnice编辑器"><span>前三次没有延迟,第四次开始延迟 1 秒,之后每次失败都会增加 1 秒的延迟。</span></p>
<p data-tool="mdnice编辑器"><span>当连接被延迟时,其在<code><span>SHOW PROCESSLIST</span></code><span>中的状态是<code><span>Waiting in connection_control plugin</span></code><span>:</span></span></span></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code><span>mysql&gt;&nbsp;show<span>&nbsp;processlist<span>;<span><br><span>+------+-----------------+-----------------+------+---------+--------+--------------------------------------+------------------+<span><br><span>| Id &nbsp; | User &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| Host &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| db &nbsp; | Command | Time &nbsp; | State &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| Info &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<span><br><span>+------+-----------------+-----------------+------+---------+--------+--------------------------------------+------------------+<span><br><span>| &nbsp; &nbsp;5 | event_scheduler | localhost &nbsp; &nbsp; &nbsp; | NULL | Daemon &nbsp;| 418840 | Waiting on empty queue &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | NULL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<span><br><span>| 1179 | root &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| localhost &nbsp; &nbsp; &nbsp; | NULL | Query &nbsp; | &nbsp; &nbsp; &nbsp;0 | init &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp;show<span>&nbsp;processlist<span>&nbsp;|<span><br><span>|&nbsp;1187<span>&nbsp;| root &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp;10.0.0.75<span>:40920<span>&nbsp;|&nbsp;NULL<span>&nbsp;|&nbsp;Connect<span>&nbsp;| &nbsp; &nbsp; &nbsp;3<span>&nbsp;| Waiting&nbsp;in<span>&nbsp;connection_control&nbsp;plugin<span>&nbsp;|&nbsp;NULL<span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<span><br><span>+------+-----------------+-----------------+------+---------+--------+--------------------------------------+------------------+<span><br>3<span>&nbsp;rows<span>&nbsp;in<span>&nbsp;set<span>,&nbsp;1<span>&nbsp;warning<span>&nbsp;(0.00<span>&nbsp;sec)<span><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></pre>
<p data-tool="mdnice编辑器"><span>接下来我们看看该插件的使用方法、相关参数、禁用方法、注意事项以及实现细节。</span></p>
<h1 data-tool="mdnice编辑器"><span style="color: rgba(0, 128, 0, 1)">使用方法</span></h1>
<p data-tool="mdnice编辑器"><strong>安装插件</strong></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code>INSTALL<span>&nbsp;PLUGIN<span>&nbsp;CONNECTION_CONTROL&nbsp;SONAME<span>&nbsp;'connection_control.so'<span>;<span><br>INSTALL<span>&nbsp;PLUGIN<span>&nbsp;CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS&nbsp;SONAME<span>&nbsp;'connection_control.so'<span>;<span><br></span></span></span></span></span></span></span></span></span></span></code></span></pre>
<p data-tool="mdnice编辑器"><span>其中,connection_control 是核心功能插件,connection_control_failed_login_attempts 提供记录客户端失败尝试次数的<code><span>information_schema.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS</span></code><span>表。</span></span></p>
<p data-tool="mdnice编辑器"><strong>卸载插件</strong></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code>UNINSTALL<span>&nbsp;PLUGIN<span>&nbsp;CONNECTION_CONTROL;<span><br>UNINSTALL<span>&nbsp;PLUGIN<span>&nbsp;CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS;<span><br></span></span></span></span></span></span></code></span></pre>
<p data-tool="mdnice编辑器"><span>从 MySQL 9.2 开始,引入了 Connection Control component 来替代 Connection Control plugin。</span></p>
<h1 data-tool="mdnice编辑器"><span style="color: rgba(0, 128, 0, 1)">相关参数和状态变量</span></h1>
<p data-tool="mdnice编辑器"><strong>参数</strong></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code><span>mysql&gt;&nbsp;show<span>&nbsp;variables<span>&nbsp;like<span>&nbsp;'%connection_control%'<span>;<span><br><span>+-------------------------------------------------+------------+<span><br><span>| Variable_name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Value &nbsp; &nbsp; &nbsp;|<span><br><span>+-------------------------------------------------+------------+<span><br><span>| connection_control_failed_connections_threshold | 3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<span><br><span>| connection_control_max_connection_delay &nbsp; &nbsp; &nbsp; &nbsp; | 2147483647 |<span><br><span>| connection_control_min_connection_delay &nbsp; &nbsp; &nbsp; &nbsp; | 1000 &nbsp; &nbsp; &nbsp; |<span><br><span>+-------------------------------------------------+------------+<span><br><span>3 rows in&nbsp;set<span>&nbsp;(0.03<span>&nbsp;sec)<span><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></pre>
<p data-tool="mdnice编辑器"><span>其中,</span></p>
<ul class="list-paddingleft-1">
<li><span>connection_control_failed_connections_threshold:触发延迟的失败尝试次数阈值,默认为 3。</span></li>
<li><span>connection_control_min_connection_delay:首次触发延迟时的最小延迟时间,默认 1000 毫秒,即 1 秒。</span></li>
<li><span>connection_control_max_connection_delay:最大延迟时间,默认 2147483647 毫秒,相当于 24.8 天。</span></li>
</ul>
<p data-tool="mdnice编辑器"><strong>状态变量</strong></p>
<p data-tool="mdnice编辑器"><span>Connection_control_delay_generated</span></p>
<p data-tool="mdnice编辑器"><span>显示触发延迟的总次数。</span></p>
<p data-tool="mdnice编辑器"><span>除此之外,还可以通过<code><span>information_schema.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS</span></code><span>查询不同客户端的失败尝试次数,例如:</span></span></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code><span>mysql&gt;&nbsp;select<span>&nbsp;*&nbsp;from<span>&nbsp;information_schema.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS;<span><br><span>+----------------------+-----------------+<span><br><span>| USERHOST &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | FAILED_ATTEMPTS |<span><br><span>+----------------------+-----------------+<span><br><span>| 'root'@'10.0.0.108' &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5 |<span><br><span>| 'root'@'127.0.0.1' &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4 |<span><br><span>| 'root1'@'10.0.0.108' | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7 |<span><br><span>+----------------------+-----------------+<span><br><span>3 rows in&nbsp;set<span>&nbsp;(0.00<span>&nbsp;sec)<span><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></pre>
<h1 data-tool="mdnice编辑器"><span style="color: rgba(0, 128, 0, 1)">如何禁用延迟功能</span></h1>
<p data-tool="mdnice编辑器"><span>以下两种方法都可以:</span></p>
<ol class="list-paddingleft-1">
<li><span>卸载插件。</span></li>
<li><span>将 connection_control_failed_connections_threshold 设置为 0。</span></li>
</ol>
<h1 data-tool="mdnice编辑器"><span style="color: rgba(0, 128, 0, 1)">注意事项</span></h1>
<p data-tool="mdnice编辑器"><span>1. 当用户连续多次登录失败后,即使后续输入正确密码,首次成功登录仍会被延迟(仅限首次成功登录,后续登录不受影响)。这种设计虽然可能不符合部分用户的习惯,但从防止暴力破解的角度来看是合理的。如果正确密码不触发延迟,攻击者便可通过是否存在延迟来判断密码是否正确,这样就会削弱防暴力破解的效果。</span></p>
<p data-tool="mdnice编辑器"><span>2. 修改 connection_control_failed_connections_threshold 会:</span></p>
<ul class="list-paddingleft-1">
<li><span>将 Connection_control_delay_generated 重置为 0。</span></li>
<li><span>清空 information_schema.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS。</span></li>
</ul>
<p data-tool="mdnice编辑器"><span>如果某个用户的失败次数过多,但希望在输入正确密码时不再等待,可以通过以下命令清空其延迟状态:</span></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code>SET<span>&nbsp;GLOBAL<span>&nbsp;connection_control_failed_connections_threshold =&nbsp;DEFAULT<span>;<span><br></span></span></span></span></code></span></pre>
<p data-tool="mdnice编辑器"><span>3. 被延迟的连接依旧会占用连接数。</span></p>
<p data-tool="mdnice编辑器"><span>如果 connection_control_min_connection_delay 设置过大,且攻击端重试频率很高,可能导致连接数被耗尽,影响正常用户的连接。</span></p>
<h1 data-tool="mdnice编辑器"><span style="color: rgba(0, 128, 0, 1)">实现细节</span></h1>
<p data-tool="mdnice编辑器"><span>以下是 Connection Control plugin 被调用的时机:</span></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code><span>static<span>&nbsp;<span>int<span>&nbsp;<span>check_connection<span>(THD *thd)<span>&nbsp;<span>{<span><br><span>&nbsp; ...<span><br>if<span>&nbsp;(!thd-&gt;m_main_security_ctx.host().length) &nbsp;// If TCP/IP connection<span><br><span>&nbsp; {<span><br><span>&nbsp; &nbsp; ...<span><br><span>&nbsp; &nbsp;&nbsp;if<span>&nbsp;(acl_check_host(thd, thd-&gt;m_main_security_ctx.host().str,<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;main_sctx_ip.str)) {&nbsp;// 检查客户端IP是否允许连接到 MySQL 服务器<span><br><span>&nbsp; &nbsp; &nbsp;&nbsp;/* HOST_CACHE stats updated by acl_check_host(). */<span><br><span>&nbsp; &nbsp; &nbsp; my_error(ER_HOST_NOT_PRIVILEGED, MYF(0<span>),<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;thd-&gt;m_main_security_ctx.host_or_ip().str);<span><br><span>&nbsp; &nbsp; &nbsp;&nbsp;return1<span>;<span><br><span>&nbsp; &nbsp; }<span><br><span>&nbsp; }&nbsp;<span><br><span>&nbsp; ...<span><br><span>&nbsp; auth_rc = acl_authenticate(thd, COM_CONNECT);&nbsp;// 这里验证用户密码是否正确<span><br><span><br>if<span>&nbsp;(mysql_event_tracking_connection_notify(<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; thd, AUDIT_EVENT(EVENT_TRACKING_CONNECTION_CONNECT))) {&nbsp;// 这里会调用 Connection Control 插件<span><br><span>&nbsp; &nbsp;&nbsp;return1<span>;<span><br><span>&nbsp; }<span><br><span><br><span>&nbsp; ...<span><br>return<span>&nbsp;auth_rc;<span><br><span>}<span><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></pre>
<p data-tool="mdnice编辑器"><span>首先检查客户端的 IP 是否被允许连接到 MySQL 服务器。如果 IP 地址不在允许的范围内,则提示<code><span>ERROR 1130 (HY000): Host 'xxx' is not allowed to connect to this MySQL server</span></code><span>&nbsp;。</span></span></p>
<p data-tool="mdnice编辑器"><span>接着验证用户的密码是否正确。如果密码错误,则提示<code><span>ERROR 1045 (28000): Access denied for user 'xxx'@'xxx' (using password: YES)</span></code><span>,错误在返回给客户端之前,会调用 Connection Control 插件,判断是否需要延迟连接。</span></span></p>
<p data-tool="mdnice编辑器"><span>这实际上提供了一个思路,如果担心延迟的连接占用过多的连接数,可以通过缩小用户账号的&nbsp;<code><span>host</span></code><span>&nbsp;范围,在密码验证之前拒绝不符合条件的连接,从而有效减少无效连接的占用。</span></span></p>
<p data-tool="mdnice编辑器"><span>此外,当 MySQL 实例可能暴露于公网时,切忌将 host 设置为<code><span>%</span></code><span>,<span>否则数据库将面临较高的恶意攻击风险。</span></span></span></p>
<p data-tool="mdnice编辑器"><span>接下来我们看看 &nbsp;Connection Control 触发延迟的实现逻辑。</span></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code><span>bool<span>&nbsp;<span>Connection_delay_action::notify_event<span>(<span><br><span>&nbsp; &nbsp; MYSQL_THD thd, Connection_event_coordinator_services *coordinator,<span><br><span>&nbsp; &nbsp;&nbsp;<span>const<span>&nbsp;mysql_event_connection *connection_event,<span><br><span>&nbsp; &nbsp; Error_handler *error_handler)<span>&nbsp;<span>{<span><br><span>&nbsp; DBUG_TRACE;<span><br>bool<span>&nbsp;error =&nbsp;false<span>;<span><br>constunsignedint<span>&nbsp;subclass = connection_event-&gt;event_subclass;<span><br><span>&nbsp; Connection_event_observer *self =&nbsp;this<span>;<span><br>// 只处理连接建立和用户切换事件<span><br>if<span>&nbsp;(subclass != MYSQL_AUDIT_CONNECTION_CONNECT &amp;&amp;<span><br><span>&nbsp; &nbsp; &nbsp; subclass != MYSQL_AUDIT_CONNECTION_CHANGE_USER)<span><br><span>&nbsp; &nbsp;&nbsp;return<span>&nbsp;error;<span><br><span><br><span>RD_lock&nbsp;<span>rd_lock<span>(m_lock)<span>;<span><br>// 获取参数 connection_control_failed_connections_threshold 的值<span><br>const<span>&nbsp;int64 threshold =&nbsp;this<span>-&gt;get_threshold();<span><br><span><br>// 如果 connection_control_failed_connections_threshold 小于等于 0,则直接返回,相当于禁用了插件<span><br>if<span>&nbsp;(threshold &lt;= DISABLE_THRESHOLD)&nbsp;return<span>&nbsp;error;<span><br><span><br><span>&nbsp; int64 current_count =&nbsp;0<span>;<span><br>bool<span>&nbsp;user_present =&nbsp;false<span>;<span><br><span>&nbsp; Sql_string userhost;<span><br>// 根据当前线程信息生成用户标识,格式为 user@host<span><br><span>&nbsp; make_hash_key(thd, userhost);<span><br><span><br><span>&nbsp; DBUG_PRINT("info"<span>, ("Connection control : Connection event lookup for: %s"<span>,<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; userhost.c_str()));<span><br><span><br>// 从哈希表中查找该用户的失败连接次数<span><br><span>&nbsp; user_present = m_userhost_hash.match_entry(userhost, (void<span>&nbsp;*)&amp;current_count)<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;?&nbsp;false<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;:&nbsp;true<span>;<span><br>// 如果该用户的失败连接次数大于或等于阈值,则触发延迟<span><br>if<span>&nbsp;(current_count &gt;= threshold || current_count &lt;&nbsp;0<span>) {<span><br><span>&nbsp; &nbsp;&nbsp;// 根据失败次数计算延迟时间<span><br><span>&nbsp; &nbsp;&nbsp;const<span>&nbsp;ulonglong wait_time = get_wait_time((current_count +&nbsp;1<span>) - threshold);<span><br><span>&nbsp; &nbsp;&nbsp;// 触发状态变量自增(Connection_control_delay_generated)<span><br><span>&nbsp; &nbsp;&nbsp;if<span>&nbsp;((error = coordinator-&gt;notify_status_var(<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;self, STAT_CONNECTION_DELAY_TRIGGERED, ACTION_INC))) {<span><br><span>&nbsp; &nbsp; &nbsp; error_handler-&gt;handle_error(<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ER_CONN_CONTROL_STAT_CONN_DELAY_TRIGGERED_UPDATE_FAILED);<span><br><span>&nbsp; &nbsp; }<span><br><span>&nbsp; &nbsp;&nbsp;// 执行延迟等待<span><br><span>&nbsp; &nbsp; rd_lock.unlock();<span><br><span>&nbsp; &nbsp; conditional_wait(thd, wait_time);<span><br><span>&nbsp; &nbsp; rd_lock.lock();<span><br><span><br><span>&nbsp; &nbsp; DBUG_EXECUTE_IF("delay_after_connection_delay"<span>, sleep(2<span>););<span><br><span>&nbsp; }<span><br><span><br>if<span>&nbsp;(connection_event-&gt;status) {<span><br><span>&nbsp; &nbsp;&nbsp;// 连接失败,更新哈希表中的失败计数<span><br><span>&nbsp; &nbsp;&nbsp;if<span>&nbsp;(m_userhost_hash.create_or_update_entry(userhost)) {<span><br><span>&nbsp; &nbsp; &nbsp; error_handler-&gt;handle_error(<span><br><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ER_CONN_CONTROL_FAILED_TO_UPDATE_CONN_DELAY_HASH, userhost.c_str());<span><br><span>&nbsp; &nbsp; &nbsp; error =&nbsp;true<span>;<span><br><span>&nbsp; &nbsp; }<span><br><span>&nbsp; }&nbsp;else<span>&nbsp;{<span><br><span>&nbsp; &nbsp;&nbsp;// 连接成功,从 m_userhost_hash 表中删除该用户对应的记录<span><br><span>&nbsp; &nbsp;&nbsp;if<span>&nbsp;(user_present) {<span><br><span>&nbsp; &nbsp; &nbsp; (void<span>)m_userhost_hash.remove_entry(userhost);<span><br><span>&nbsp; &nbsp; }<span><br><span>&nbsp; }<span><br><span><br>return<span>&nbsp;error;<span><br><span>}<span><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></pre>
<p data-tool="mdnice编辑器"><span>这个函数中需要注意的地方有两点:</span></p>
<ol class="list-paddingleft-1">
<li>
<p><span>延迟时间。</span></p>
<p><span>延迟时间 =&nbsp;<code><span>(当前失败次数 + 1 - 阈值)</span></code><span>秒,失败次数越多,延迟时间越长。</span></span></p>
<p><span>延迟时间受到最小值和最大值 (connection_control_min_connection_delay 和 connection_control_max_connection_delay) 的限制。</span></p>
</li>
<li>
<p><span>USERHOST 的构造规则。</span></p>
<p><span>如果连接的用户名在<code><span>mysql.user</span></code><span>表中存在,则 USERHOST 的 host 部分取自于<code><span>mysql.user</span></code><span>表中该用户的<code><span>host</span></code><span>字段值。</span></span></span></span></p>
<p><span>如果用户名不存在,则 host 部分会使用客户端的 IP 地址。</span></p>
</li>
</ol>
<p data-tool="mdnice编辑器"><span>看下面这个示例。</span></p>
<pre data-tool="mdnice编辑器"><span data-cacheurl="" data-remoteid="" data-lazy-bgimg="https://mmbiz.qpic.cn/mmbiz_svg/BO1qQiajiacVll2lZZ7QEHpXjMNOicU5mpbzLf0oBADHQxib42Sa889gp48hW5BxG68nwiaCZAjo0rmp8W38fsYJ7olk0owCVH0Md/640?wx_fmt=svg&amp;from=appmsg" data-fail="0"><code><span>mysql&gt;&nbsp;select<span>&nbsp;user<span>,host&nbsp;from<span>&nbsp;mysql.user&nbsp;whereuser<span>='root'and<span>&nbsp;host='%'<span>;<span><br><span>+------+------+<span><br><span>| user | host |<span><br><span>+------+------+<span><br><span>| root | % &nbsp; &nbsp;|<span><br><span>+------+------+<span><br><span>1 row in&nbsp;set<span>&nbsp;(0.00<span>&nbsp;sec)<span><br><span><br># 用户 root 在 mysql.user 表中存在,且 host 为 %,所以生成的 USERHOST 是 'root'@'%'。<span><br># mysql -h10.0.0.108 -uroot -p123<span><br><span>mysql: &nbsp;Using<span>&nbsp;a&nbsp;passwordon<span>&nbsp;the command line&nbsp;interface<span>&nbsp;can be insecure.<span><br>ERROR1045<span>&nbsp;(28000<span>):&nbsp;Access<span>&nbsp;denied&nbsp;foruser'root'<span>@'10.0.0.75'<span>&nbsp;(usingpassword<span>: YES)<span><br><span><br><span>mysql&gt;&nbsp;select<span>&nbsp;*&nbsp;from<span>&nbsp;information_schema.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS;<span><br><span>+------------+-----------------+<span><br><span>| USERHOST &nbsp; | FAILED_ATTEMPTS |<span><br><span>+------------+-----------------+<span><br><span>| 'root'@'%' | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1 |<span><br><span>+------------+-----------------+<span><br><span>1 row in&nbsp;set<span>&nbsp;(0.00<span>&nbsp;sec)<span><br><span><br># 用户 root1 在 mysql.user 表中不存在,所以生成的 USERHOST 是 'root1'@'客户端IP'。<span><br># mysql -h10.0.0.108 -uroot1 -p123<span><br><span>mysql: &nbsp;Using<span>&nbsp;a&nbsp;passwordon<span>&nbsp;the command line&nbsp;interface<span>&nbsp;can be insecure.<span><br>ERROR1045<span>&nbsp;(28000<span>):&nbsp;Access<span>&nbsp;denied&nbsp;foruser'root1'<span>@'10.0.0.75'<span>&nbsp;(usingpassword<span>: YES)<span><br><span><br><span>mysql&gt;&nbsp;select<span>&nbsp;*&nbsp;from<span>&nbsp;information_schema.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS;<span><br><span>+---------------------+-----------------+<span><br><span>| USERHOST &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| FAILED_ATTEMPTS |<span><br><span>+---------------------+-----------------+<span><br><span>| 'root1'@'10.0.0.75' | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1 |<span><br><span>+---------------------+-----------------+<span><br><span>1 row in&nbsp;set<span>&nbsp;(0.00<span>&nbsp;sec)<span><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></span></pre>
<h1 data-tool="mdnice编辑器"><span style="color: rgba(0, 128, 0, 1)">参考资料</span></h1>
<ol class="list-paddingleft-1">
<li><span>https://dev.mysql.com/doc/refman/8.4/en/connection-control-plugin-installation.html</span></li>
<li><span>https://dev.mysql.com/doc/refman/9.2/en/connection-control-component.html</span></li>
<li><span>https://dev.mysql.com/blog-archive/the-connection_control-plugin-keeping-brute-force-attack-in-check/</span></li>
</ol><br><br>
来源:https://www.cnblogs.com/ivictor/p/19044086
頁: [1]
查看完整版本: MySQL 密码防暴力破解插件:Connection Control