ホームページ データベース 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 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Windows 11 シャットダウン プロンプト タスク ホスト ウィンドウ タスク ホストがシャットダウン タスク ソリューションを実行しています Windows 11 シャットダウン プロンプト タスク ホスト ウィンドウ タスク ホストがシャットダウン タスク ソリューションを実行しています Feb 12, 2024 pm 12:40 PM

最近、多くの Win11 ユーザーが、シャットダウン時に、taskhostwindow タスク ホストがシャットダウン タスクを実行しているというメッセージが表示されると報告しています。ユーザーは、ローカル レジストリ エディターの下のデスクトップ フォルダーに入り、右側のウィンドウで AutoEndTasks を選択して設定できます。このサイトは、シャットダウン時にこの問題の解決策をユーザーに丁寧に紹介します。 Windows 11 のシャットダウンでは、taskhostwindow タスク ホストがシャットダウン タスクを実行していることを示すメッセージが表示されます。 解決策 1. 次の図に示すように、win キー + r キーの組み合わせを使用し、「regedit」と入力して Enter キーを押します。 2. [HKEY]を検索します

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 ブルー スクリーン エラーが発生することがあります。これを行うには、コンピュータを再起動する前に、すべての外部デバイスを取り外しておく必要があります。

Windows 11 で aggregator host.exe が安全かどうかを確認する方法 Windows 11 で aggregator host.exe が安全かどうかを確認する方法 Apr 13, 2023 pm 04:22 PM

タスクを終了したりアプリケーションを停止したりするためにタスク マネージャーを起動すると、通常、多数のプロセスが実行されていることがわかります。これはまったく正常なことです。ただし、まったく気づいていないシステム リソースを使用しているプログラムが存在することがあります。これらのプロセスの 1 つはアグリゲーター host.exe であり、最近ユーザーの間で混乱を引き起こしています。これらのプロセスの一部は正当な Windows 要件である可能性がありますが、その他のプロセスはバックグラウンドで実行され、ユーザーの認識や同意なしに問題を引き起こす悪意のあるプログラムである可能性があります。 Windows 11 でタスク マネージャーを起動する 5 つの方法を説明した後、aggregator host.exe が安全かウイルスかを確認する方法を説明します。ついていく

マスターとホストの違いは何ですか マスターとホストの違いは何ですか Sep 28, 2023 pm 01:34 PM

マスターとホストの違いは次のとおりです: 1. ホストはクライアントまたはサーバーの役割を果たすことができますが、マスターは分散システム内の他のスレーブ サーバーの調整と管理を担当する中央サーバーです; 2. ホストは通常​​のコンピュータ デバイスであり、マスターです通常、より高い処理能力を持ち、タスクの処理と分散、データの管理、システム全体の安定性の維持にリソースが使用されます; 3. ホストはネットワーク内のノードであり、マスターはネットワーク内で中心的な役割を果たすサーバーです。分散システム。

ホストへのルートがない場合の対処方法 ホストへのルートがない場合の対処方法 Oct 07, 2023 am 10:50 AM

「ホストへのルートがありません」の解決策には、ネットワーク接続の確認、IP アドレスとポートの確認、ファイアウォール構成の確認、ルーティング構成の確認、ネットワーク デバイス構成の確認、ネットワーク サービス ステータスの確認、ネットワーク構成の確認と連絡先が含まれます。ネットワーク管理者。詳細な紹介: 1. ネットワーク接続をチェックして、クライアントとターゲット ホスト間のネットワーク接続が正常であることを確認します。ping コマンドまたはその他のネットワーク ツールを使用してネットワーク接続をテストし、ネットワーク ケーブルなどのハードウェア デバイスが接続されているかどうかを確認します。 、ワイヤレス ネットワーク、ルーターが正常に動作していることを確認してください。ネットワーク接続が安定していることなどを確認してください。

enum モジュールを使用して Python 2.x で列挙型を定義する方法 enum モジュールを使用して Python 2.x で列挙型を定義する方法 Jul 29, 2023 pm 09:33 PM

enum モジュールを使用して Python2.x で列挙型を定義する方法 はじめに: 列挙型は、変数の値を限られた範囲に制限するデータ型です。列挙型を使用すると、コードがより明確で読みやすくなります。 Python2.x では、enum モジュールを使用して列挙型を定義できます。この記事では、enum モジュールを使用して列挙型を定義および使用する方法と、対応するコード例を紹介します。 enum モジュールのインポート enum モジュールを使用する前に、まずモジュールをインポートする必要があります。存在する

ホストファイルはどこにありますか ホストファイルはどこにありますか Jan 04, 2021 am 11:25 AM

ホスト ファイルはパス「C:\Windows\System32\drivers\etc」にあります。ホスト ファイルはメモ帳などの通常のテキスト編集ソフトウェアで開くことができるプレーン テキスト ファイルです。ホスト ファイルの機能は次のとおりです。 IP アドレスとホスト名とのマッピング関係を含めます。

Windows 11 で WMI プロバイダー ホストの CPU 使用率が高い問題を解決する 4 つの簡単なヒント Windows 11 で WMI プロバイダー ホストの CPU 使用率が高い問題を解決する 4 つの簡単なヒント Apr 18, 2023 pm 08:25 PM

WMIProviderHost プロセスは、Windows 11 で重要な役割を果たします。これにより、他のアプリケーションがコンピュータに関する情報を要求できるようになります。 WMIProviderHost に関連するプロセスは通常、バックグラウンドで実行されるため、通常は大量のシステム リソースを消費しません。ただし、このサービスは他のアプリケーションのせいで、時々 CPU パワーの 50% 以上を使用すると報告されています。コンピュータのプロセッサをほぼ最大能力で長時間実行すると、過熱やシステム コンポーネントの損傷につながる可能性があるため、心配です。今日のチュートリアルでは、WMIProviderHost が Windows 11 上の C で動作する理由を見ていきます。

See all articles