Mysql学习用户认证原理与实现
这是有事没事时做的关于我们来理解在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);//验证用户名和密码 }
上面的源码主要做了如下几件事情:
- 获取客户端的IP和主机名
- acl_check_host函数验证USER表中是否存在相应的IP或HOST,如果不存在直接报错
- 获取用户名和密码
- check_user函数验证用户名和密码(不输入用户名默认为ODBC),如果系统表中不存在匹配的报错返回
- 获取用户的权限列表,验证用户的相关属性是否合法,如连接数是否超过上限,连接是否超时,操作是否超过限制等信息,如果不合法,则报错返回。
由于在一个认证的过程中涉及到的东西比较多,各个方面吧,我不能一一跟踪,只能大概了解其中的实现流程,捡重点进行

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











최근 많은 Win11 사용자가 종료할 때 taskhostwindow 작업 호스트가 종료 작업을 실행하고 있다는 메시지가 표시된다고 보고했습니다. 무슨 일이 일어나고 있는 걸까요? 사용자는 로컬 레지스트리 편집기 아래 Desktop 폴더에 들어간 후 오른쪽 창에서 AutoEndTasks를 선택하여 설정할 수 있습니다. 이 사이트를 종료할 때 이 문제에 대한 해결책을 사용자에게 주의 깊게 소개하십시오. Windows 11 종료에서는 taskhostwindow 작업 호스트가 종료 작업을 실행 중이라는 메시지가 표시됩니다. 해결 방법 1. 아래 그림과 같이 win 키 + r 키 조합을 사용하여 "regedit"를 입력하고 Enter 키를 누릅니다. 2. [HKEY]를 검색하세요

Kernelsecuritycheckfailure(커널 검사 실패)는 비교적 일반적인 유형의 중지 코드입니다. 그러나 이유가 무엇이든 블루 스크린 오류로 인해 많은 사용자가 매우 괴로워합니다. 이 사이트에서는 사용자에게 17가지 유형을 주의 깊게 소개합니다. kernel_security_check_failure 블루 스크린에 대한 17가지 솔루션 방법 1: 모든 외부 장치 제거 사용 중인 외부 장치가 Windows 버전과 호환되지 않으면 Kernelsecuritycheckfailure 블루 스크린 오류가 발생할 수 있습니다. 이렇게 하려면 컴퓨터를 다시 시작하기 전에 모든 외부 장치를 분리해야 합니다.

작업을 종료하거나 응용 프로그램을 중지하기 위해 작업 관리자를 시작할 때 일반적으로 많은 수의 프로세스가 실행되고 있는 것을 발견합니다. 이것은 완전히 정상입니다. 그러나 때로는 우리가 전혀 인식하지 못하는 시스템 리소스를 사용하는 프로그램을 볼 수 있습니다. 이러한 프로세스 중 하나는 최근 사용자들 사이에 혼란을 야기하고 있는 수집기 호스트.exe입니다. 이러한 프로세스 중 일부는 합법적인 Windows 요구 사항일 수 있지만 다른 프로세스는 백그라운드에서 실행되어 사용자가 알지 못하거나 동의하지 않고 문제를 일으키는 악성 프로그램일 수 있습니다. Windows 11에서 작업 관리자를 시작할 수 있는 5가지 방법을 살펴본 후 aggregator host.exe가 안전한지 또는 바이러스인지 확인하는 방법을 보여 드리겠습니다. 유지하다

마스터와 호스트의 차이점은 다음과 같습니다. 1. 호스트는 클라이언트 또는 서버 역할을 할 수 있지만 마스터는 분산 시스템에서 다른 슬레이브 서버를 조정하고 관리하는 중앙 서버입니다. 2. 호스트는 일반 컴퓨터 장치이며 마스터입니다. 일반적으로 처리 능력이 더 높으며 작업을 처리 및 분산하고 데이터를 관리하며 전체 시스템의 안정성을 유지하는 데 사용됩니다. 3. 호스트는 네트워크의 노드이고 마스터는 네트워크에서 핵심 역할을 하는 서버입니다. 분산 시스템.

"호스트에 대한 경로 없음"에 대한 해결 방법에는 네트워크 연결 확인, IP 주소 및 포트 확인, 방화벽 구성 확인, 라우팅 구성 확인, 네트워크 장치 구성 확인, 네트워크 서비스 상태 확인, 네트워크 구성 확인 및 연결이 포함됩니다. 네트워크 관리자. 자세한 소개: 1. 네트워크 연결을 확인하여 클라이언트와 대상 호스트 간의 네트워크 연결이 정상적인지 확인하십시오. ping 명령이나 기타 네트워크 도구를 통해 네트워크 연결을 테스트하고 네트워크 케이블과 같은 하드웨어 장치가 있는지 확인할 수 있습니다. , 무선 네트워크 및 라우터가 제대로 작동하는지 확인하세요. 네트워크 연결이 안정적인지 확인하세요.

Python2.x에서 열거형을 정의하기 위해 enum 모듈을 사용하는 방법 소개: 열거형은 변수의 값을 제한된 범위로 제한하는 데이터 유형입니다. 열거형을 사용하면 코드를 더 명확하고 읽기 쉽게 만들 수 있습니다. Python2.x에서는 enum 모듈을 사용하여 열거 유형을 정의할 수 있습니다. 이 글에서는 enum 모듈을 사용하여 열거 유형을 정의하고 사용하는 방법을 소개하고 해당 코드 예제를 제공합니다. enum 모듈 가져오기 enum 모듈을 사용하기 전에 먼저 모듈을 가져와야 합니다. 존재하다

호스트 파일은 "C:\Windows\System32\drivers\etc" 경로에 있습니다. 호스트 파일은 메모장과 같은 일반 텍스트 편집 소프트웨어로 열 수 있는 일반 텍스트 파일입니다. 호스트 이름과 IP 주소 매핑 관계를 포함합니다.

WMIProviderHost 프로세스는 Windows 11에서 중요한 역할을 합니다. 이를 통해 다른 응용 프로그램이 컴퓨터에 대한 정보를 요청할 수 있습니다. WMIProviderHost와 관련된 프로세스는 일반적으로 백그라운드에서 실행되므로 일반적으로 많은 양의 시스템 리소스를 소비하지 않습니다. 하지만 이 서비스는 다른 애플리케이션으로 인해 때때로 CPU 성능의 50% 이상을 사용하는 것으로 알려졌습니다. 장시간 동안 컴퓨터 프로세서를 거의 최대 용량으로 실행하는 것은 걱정스러운 일입니다. 그렇게 하면 시스템 구성 요소가 과열되거나 손상될 수 있습니다. 오늘의 튜토리얼에서는 WMIProviderHost가 Windows 11의 C에서 작동하는 이유를 살펴보겠습니다.
