首頁 資料庫 mysql教程 Mysql学习用户认证原理与实现

Mysql学习用户认证原理与实现

Jun 07, 2016 pm 05:51 PM
enum host security user

这是有事没事时做的关于我们来理解在mysql核心代码中的用户验证原理,有兴趣的同学可以参考一下。

验证用户名和密码的过程,我们平时做一个系统的时候,很多时候都会涉及到身份验证。今天我们就来看下Mysql是如何进

行验证的。(注意是登录,不是登陆^_^)

一、用户认证原理

我们在应用程序中实现验证的方式基本上都是创建一张用户表,里面至少包含username和password两个字段,

password基本上都是加密后进行存储的。作为,对用户的限制较多,不是像我说的仅仅只有username和password

这么简单了。首先粗略的讲下访问控制。

信息系统中,访问控制分为自主访问控制(DAC)强制访问控制(MAC)。具体到DBMS,自主访问控制就是我们所熟悉

的GRANT,REVOKE,大多数数据库都支持自助的访问控制。强制访问控制就是ORACLE中的LABEL,只有很少的一些系统支持MAC。

严格来说,登录并不属于访问控制机制,而应该属于用户身份识别和认证。在Mysql中,将登录和DAC的相关接口都实现在了

sql_acl.cc中(其实说登录是用户拥有的一种权限也未尝不可,正如ORACLE中的CREATE SESSION,不过登录并不仅仅是一种权

限,还包含很多其他的属性),从文件名大家可以看出来,ACL即ACCESS CONTROL LIST,访问控制列表,这是实现访问控制的

基本方法。下图是Mysql的整个访问控制的流程

Mysql中用户管理模块的信息存储在系统表.User中,这个表不仅仅存放了授权用户的基本信息,还存放一些权限

信息。我们首先大概看一下这个表的结构。

登入後複製
登入後複製
登入後複製
 代码如下 复制代码
+-----------------------+-----------------------------------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+-----------------------+-----------------------------------+------+-----+---------+-------+

| Host | char(60) | NO | PRI | | |

| User | char(16) | NO | PRI | | |

| Password | char(41) | NO | | | |

| Select_priv | enum('N','Y') | NO | | N | |

| Insert_priv | enum('N','Y') | NO | | N | |

| Update_priv | enum('N','Y') | NO | | N | |

| Delete_priv | enum('N','Y') | NO | | N | |

| Create_priv | enum('N','Y') | NO | | N | |

| Drop_priv | enum('N','Y') | NO | | N | |

| Reload_priv | enum('N','Y') | NO | | N | |

| Shutdown_priv | enum('N','Y') | NO | | N | |

| Process_priv | enum('N','Y') | NO | | N | |

| File_priv | enum('N','Y') | NO | | N | |

| Grant_priv | enum('N','Y') | NO | | N | |

| References_priv | enum('N','Y') | NO | | N | |

| Index_priv | enum('N','Y') | NO | | N | |

| Alter_priv | enum('N','Y') | NO | | N | |

| Show_db_priv | enum('N','Y') | NO | | N | |

| Super_priv | enum('N','Y') | NO | | N | |

| Create_tmp_table_priv | enum('N','Y') | NO | | N | |

| Lock_tables_priv | enum('N','Y') | NO | | N | |

| Execute_priv | enum('N','Y') | NO | | N | |

| Repl_slave_priv | enum('N','Y') | NO | | N | |

| Repl_client_priv | enum('N','Y') | NO | | N | |

| Create_view_priv | enum('N','Y') | NO | | N | |

| Show_view_priv | enum('N','Y') | NO | | N | |

| Create_routine_priv | enum('N','Y') | NO | | N | |

| Alter_routine_priv | enum('N','Y') | NO | | N | |

| Create_user_priv | enum('N','Y') | NO | | N | |

| Event_priv | enum('N','Y') | NO | | N | |

| Trigger_priv | enum('N','Y') | NO | | N | |

| ssl_type | enum('','ANY','X509','SPECIFIED') | NO | | | |

| ssl_cipher | blob | NO | | NULL | |

| x509_issuer | blob | NO | | NULL | |

| x509_subject | blob | NO | | NULL | |

| max_questions | int(11) unsigned | NO | | 0 | |

| max_updates | int(11) unsigned | NO | | 0 | |

| max_connections | int(11) unsigned | NO | | 0 | |

| max_user_connections | int(11) unsigned | NO | | 0 | |

+-----------------------+-----------------------------------+------+-----+---------+-------+

39 rows in set (0.01 sec)
登入後複製

这个表包含了39个字段,对于我们登录来说,应该主要是使用前三个字段,即Host,User,Password。

 

登入後複製
登入後複製
登入後複製
 代码如下 复制代码
mysql>  Host,User,Password from user;

+-----------+------+----------+

| Host | User | Password |

+-----------+------+----------+

| localhost | root | |

| 127.0.0.1 | root | |

| localhost | | |

+-----------+------+----------+

3 rows in set (0.00 sec)
登入後複製

这里比我们预想的只需要用户名和密码的方式有所出入,多了一个Host字段,这个字段起到什么作用呢?!原来Mysql的登录认证不仅需要验证用户名和密码,还需要验证连接的主机地址,这样也是为了提高安全性吧。那如果我想一个用户在任何地址都可以进行登录岂不是要设置很多地址?Mysql提供了通配符,可以设置Host字段为*,这就代表可以匹配任何Host。具体看下这三行的意思,这三行的密码均为空。针对root用户,不需要输入密码,客户端的地址为本机。第三行的用户名为空,Host为localhost,说明本地的任何用户均可以进行登录,即使是个不存在的用户也可以登录成功,但是仅限于登录,没有其他相关的权限,无法进行实际操作。

二、跟踪

在Connection Manager中提到了login_connection函数用于检查用户名和密码等相关信息,其源码如下(重点的函数代码

会着色):

登入後複製
登入後複製
登入後複製
 代码如下 复制代码
static bool login_connection(THD *thd)
{
  NET *net= &thd->net;
  int error;
  DBUG_ENTER("login_connection");
  DBUG_PRINT("info", ("login_connection called by thread %lu",
                      thd->thread_id));

  /* Use "connect_timeout" value during connection phase */
  my_net_set_read_timeout(net, connect_timeout);
  my_net_set_write_timeout(net, connect_timeout);
error= check_connection(thd); //此处是验证的具体函数

  net_end_statement(thd);

  if (error)
  {                        // Wrong permissions
#ifdef __NT__
    if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
      my_sleep(1000);                /* must wait after eof() */
#endif
    statistic_increment(aborted_connects,&LOCK_status);
    DBUG_RETURN(1);
  }
  /* Connect completed, set read/write timeouts back to default */
  my_net_set_read_timeout(net, thd->variables.net_read_timeout);
  my_net_set_write_timeout(net, thd->variables.net_write_timeout);
  DBUG_RETURN(0);
}
登入後複製

此函数主要是功能是调用函数check_connection进行用户认证,由于函数check_connection过长,对其进行简化,如下所示:

static int check_connection(THD *thd)

{
  uint connect_errors= 0;
  NET *net= &thd->net;
  ulong pkt_len= 0;
  char *end;

  DBUG_PRINT("info",
             ("New connection received on %s", vio_description(net->vio)));
#ifdef SIGNAL_WITH_VIO_CLOSE
  thd->set_active_vio(net->vio);
#endif

  if (!thd->main_security_ctx.host)         // If TCP/IP connection
  {
    char ip[30];

    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
    {
      my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
      return 1;
    }
    if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
      return 1; /* The error is set by my_strdup(). */
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
    vio_in_addr(net->vio,&thd->remote.sin_addr);
    if (!(specialflag & SPECIAL_NO_RESOLVE))
    {
      vio_in_addr(net->vio,&thd->remote.sin_addr);
      thd->main_security_ctx.host=
        ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
      /* Cut very long hostnames to avoid possible overflows */
      if (thd->main_security_ctx.host)
      {
        if (thd->main_security_ctx.host != my_localhost)
          thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
                                          HOSTNAME_LENGTH)]= 0;
        thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
      }
      if (connect_errors > max_connect_errors)
      {
        my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip);
        return 1;
      }
    }
    ...

if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))//此处验证主机名或IP是否存在

    {
      my_error(ER_HOST_NOT_PRIVILEGED, MYF(0),
               thd->main_security_ctx.host_or_ip);
      return 1;
    }
  }
  else /* Hostname given means that the connection was on a socket */
  {
   ...
  }
  vio_keepalive(net->vio, TRUE);

  ...

  char *user= end;
  char *passwd= strend(user)+1;
  uint user_len= passwd - user - 1;
  char *db= passwd;
  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
  char user_buff[USERNAME_LENGTH + 1];    // buffer to store user in utf8
  uint dummy_errors;

  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
    (uchar)(*passwd++) : strlen(passwd);
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
    db + passwd_len + 1 : 0;
  uint db_len= db ? strlen(db) : 0;

  if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
  {
    inc_host_errors(&thd->remote.sin_addr);
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
    return 1;
  }

...
  /* If username starts and ends in "'", chop them off */
  if (user_len > 1 && user[0] == ''' && user[user_len - 1] == ''')
  {
    user[user_len-1]= 0;
    user++;
    user_len-= 2;
  }

  if (thd->main_security_ctx.user)
    x_free(thd->main_security_ctx.user);
  if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
    return 1; /* The error is set by my_strdup(). */
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);//验证用户名和密码

}
登入後複製

上面的源码主要做了如下几件事情:

  1. 获取客户端的IP和主机名
  2. acl_check_host函数验证USER表中是否存在相应的IP或HOST,如果不存在直接报错
  3. 获取用户名和密码
  4. check_user函数验证用户名和密码(不输入用户名默认为ODBC),如果系统表中不存在匹配的报错返回
  5. 获取用户的权限列表,验证用户的相关属性是否合法,如连接数是否超过上限,连接是否超时,操作是否超过限制等信息,如果不合法,则报错返回。

由于在一个认证的过程中涉及到的东西比较多,各个方面吧,我不能一一跟踪,只能大概了解其中的实现流程,捡重点进行

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

windows11關機提示task host window任務宿主正在執行關閉任務的解決方法 windows11關機提示task host window任務宿主正在執行關閉任務的解決方法 Feb 12, 2024 pm 12:40 PM

近期不少的win11用戶們反映關機的時候提示taskhostwindow任務宿主正在執行關閉任務,那麼這是怎麼回事?使用者可以進入到本機登錄編輯程式下的Desktop資料夾,然後在右邊的視窗中選擇AutoEndTasks來進行設定就可以了。以下就讓本站來為用戶們來仔細的介紹一下關機出現這個問題的解決方法吧。 windows11關機提示taskhostwindow任務宿主正在執行關閉任務的解決方法1、使用組合鍵win鍵+r鍵,輸入“regedit”,回車,如下圖所示。 2、尋找[HKEY

如何檢查聚合器 host.exe 在 Windows 11 中是否安全 如何檢查聚合器 host.exe 在 Windows 11 中是否安全 Apr 13, 2023 pm 04:22 PM

當我們啟動任務管理器以終止任務或停止應用程式時,我們通常會發現大量進程正在運行。這是完全正常的。但是,有時我們會看到一些程式正在使用我們完全不知道的系統資源。其中一個進程是聚合器 host.exe,它最近在用戶中引起了一些混亂。其中一些進程可能是合法的 Windows 要求,但其他進程可能是在後台運行並在用戶不知情或未經用戶同意的情況下導致問題的惡意程式。在我們看到您可以在 Windows 11 中啟動工作管理員的五種方式之後,我們將向您展示如何檢查聚合器 host.exe 是安全性還是病毒。跟上

解決kernel_security_check_failure藍色畫面的17種方法 解決kernel_security_check_failure藍色畫面的17種方法 Feb 12, 2024 pm 08:51 PM

Kernelsecuritycheckfailure(內核檢查失敗)就是一個比較常見的停止代碼類型,可藍屏錯誤出現不管是什麼原因都讓很多的有用戶們十分的苦惱,下面就讓本站來為用戶們來仔細的介紹一下17種解決方法吧。 kernel_security_check_failure藍色畫面的17種解決方法方法1:移除全部外部裝置當您使用的任何外部裝置與您的Windows版本不相容時,則可能會發生Kernelsecuritycheckfailure藍色畫面錯誤。為此,您需要在嘗試重新啟動電腦之前拔下全部外部裝置。

no route to host怎麼辦 no route to host怎麼辦 Oct 07, 2023 am 10:50 AM

「no route to host」的解決方案有檢查網路連線、檢查IP位址和連接埠、檢查防火牆設定、檢查路由設定、檢查網路設備設定、檢查網路服務狀態、檢查網路設定和聯絡網路管理員等。詳細介紹:1、檢查網路連接,確保客戶端和目標主機之間的網路連接正常,可以嘗試透過ping指令或其他網路工具測試網路連通性,檢查網路線、無線網路、路由器等硬體設備是否正常運作,確保網路連線穩定等等。

master和host的差別是什麼 master和host的差別是什麼 Sep 28, 2023 pm 01:34 PM

master和host的區別有:1、host可以扮演客戶端或伺服器的角色,而master是分散式系統中負責協調和管理其他從伺服器的中央伺服器;2、host是普通的電腦設備,而master通常具有更高的處理能力和資源,用於處理和分發任務、管理資料和維護整個系統的穩定性;3、host是網路中的一個節點,而master是在分散式系統中擔任核心角色的伺服器。

Python 2.x 中如何使用enum模組定義枚舉類型 Python 2.x 中如何使用enum模組定義枚舉類型 Jul 29, 2023 pm 09:33 PM

Python2.x中如何使用enum模組定義枚舉類型引言:枚舉是一種資料類型,它將變數的取值限定在一個有限的範圍內,使用枚舉類型可以使程式碼更加清晰和可讀。在Python2.x中,我們可以使用enum模組來定義枚舉類型。本文將介紹如何使用enum模組來定義和使用枚舉類型,並給出對應的程式碼範例。導入enum模組在使用enum模組之前,首先需要導入模組。在

Flask-Security: 在Python web應用程式中新增使用者驗證和密碼加密 Flask-Security: 在Python web應用程式中新增使用者驗證和密碼加密 Jun 17, 2023 pm 02:28 PM

Flask-Security:在Pythonweb應用程式中添加用戶身份驗證和密碼加密隨著互聯網的不斷發展,越來越多的應用程式需要用戶身份驗證和密碼加密來保護用戶資料的安全性。而在Python語言中,有一個非常流行的Web架構-Flask。 Flask-Security是基於Flask框架的擴充庫,它可以幫助開發人員在Pythonweb應用程式中輕

host檔案在哪裡 host檔案在哪裡 Jan 04, 2021 am 11:25 AM

host檔案位於路徑「C:\Windows\System32\drivers\etc」下;host檔案是純文字的文件,用普通的文字編輯軟體,如記事本等都能開啟;host檔案的作用是包含IP位址和Host name主機名稱的映射關係。

See all articles