상세 컨텐츠

본문 제목

mySQL 접근 권한 시스템

프로그래밍/DB

by 라제폰 2008. 12. 22. 17:51

본문

6. Mysql 접근 권한 시스템

mysql 은 진보적이지만 비표준적인 보안/권한 시스템을 가지고 있다. 이번 장에서는 이것이
어떻게 작동하는지를 설명하고 있다.

6.1 권한 시스템이란 무엇인가?
Mysql 권한 시스템의 주요 기능은 데이터베이스에서 select, insert, update, delete 권한
을 호스트의 사용자 이름과 관련짓는 것이다.

추가적인 기능에는 익명 사용자  기능과 LOAD DATA INFILE 과 관리자 오퍼레이션과 같은 my
sql만의  특수한 권한을 허용하는 부분이 포함되어 있다.


Mysql에서 인증을 목적으로 사용하는 사용자 이름은 유닉스 사용자 이름(로그인 이름)이나
위도우 사용자 이름고는 전혀 관계가 없다는 것!을 기억하자. 대부분 mysql 클라이언트는 m
ysql 사용자 이름으로 현재의 유닉스 사용자 이름을 사용하여 접속하려 할 것이다. 그렇지
만 이건 오직 편의를 위해서이다. 클라이언트 프로그램은 -u 나 --user 옵션으로 지정한 다
른 이름을 허용한다. 이것은 mysql 사용자 이름에 비밀번호를 설정하지 않으면 데이터베이
스의 보안에 문제가 생길 수 있다는 것을 의미한다. 어떤 이름을 사용하여 서버에 접속하려
고 하는 사람은 각 이름에 비밀번호가 설정되어 있지 않다면 접속에 성공할 것이다.

유닉스 사용자 이름이 일반적으로 8글자로 제한되어 있는 것과 다르게 mysql 사용자 이름은
16글자까지 사용할 수 있다.

mysql 비밀번호는 유닉스의 비밀번호와 아무 관련이 없다. 유닉스 머신에 로그인할 때 사용
하는 비밀번호와 데이터베이스에 접속할 때 사용하는 비밀번호는 전혀 관련이 없다. 또한 m
ysql은 유닉스 로그인 프로세스에서 사용하는 것과 다른 알고리즘으로 비밀번호를 암호화한
다.


6.2 mysql 서버에 접속하기

mysql 클라이언트 프로그램은 일반적으로 연결 패러미터(매개 변수)가 필요하다.: 연결할
호스트, 사용자 이름, 비밀번호. 예를 들어 mysql 클라이언트는 다음과 같이 시작할 수 있
다. (선택 인자는 [ ] 로 닫는다)

shell>; mysql [-h host_name] [-u user_name] [-pyour_pass]


-p와 뒤에 붙은 비밀번호 사이에는 공간이 없다는 것을 기억하자.

-h, -u, -p를 대체할 수 있는 형식으로는 --host=host_name, --user=user_name and --passw
ord=your_pass  이 있다.

mysql은 커맨드 라인에서 연결 매개변수가 빠져있을 때는 기본 값을 사용한다. 기본 호스트
이름은 localhost 이고 기본 사용자 이름은 유닉스 로그인 이름이다.(-p 가 빠져있으면 비
밀번호는 사용하지 않는다) 그래서 만약 유닉스 사용자 이름이 joe 라면 다음의 명령은 동
일하다.:

shell> mysql -h localhost -u joe
shell> mysql -h localhost
shell> mysql -u joe
shell> mysql


다른 mysql 클라이언트도 비슷하게 작동한다.

유닉스 시스템에서 연결을 할 때 사용할 수 있는 기본 값이 있어서 클라이언트 프로그램을
사용할 때마다 명령행에서 옵션을 사용하지 않아도 된다:

ㅇ 홈 디렉토리의 '.my.cnf' 설정 파일의 [client]  섹션에서 연결 변수를 설정할 수 있다.
파일에서 이와 연관된 섹션은 다음과 같다:
[client]
host=host_name
user=user_name
password=your_pass

4.14.4 [option files] 참고.

ㅇ 환경 변수를 사용하여 연결 변수를 지정할 수 있다. 호스트는 MYSQL_HOST 로 지정할 수
있다. Mysql  사용자 이름은 USER, LOGNAME, 또는 LOGIN을 사용할 수 있다. (이러한 값들은
이미 유닉스 로그인 이름으로 설정되어 있을 것이다. 그러므로 바꾸지 않는게 좋다) 비밀번
호는 MYSQL_PWD로 지정할 수 있다.(그렇지만 이것은 안전하지 않다; 다음 섹션을 참고하자)

연결 변수가 여러 가지 방법을 지정되었다면 명령행에서 지정한 값이 설정 파일과 환경 변
수로 설정한 것보다 우선권을 가진다. 또한 설정 파일의 값이 환경 변수보다 우선권을 가진
다.

6. 2. 1 비밀번호의 보안 유지

다른 사용자가 발견할 수 있게 비밀번호를 지정하는 방법은 권하지 않는다. 클라이언트 프
로그램을 실행할 때 비밀번호를 지정하는 방법은 아래와 같으며 각 방법마다 위험도를 같이
설명하였다:

ㅇ 명령행에서 -pyour_pass 또는 --password=your_pass 옵션 사용.  이 방법은 편리하지만
위험한 방법이다. 비밀번호를 시스템 상황 프로그램(ps 등)을 통해 볼 수 있기 때문에 다른
사용자가 명랭행으로 볼 수 있다.(mysql 클라이언트는 일반적으로 초기화되는 동안 명령행
인자를 0으로 덮어씌운다. 그렇지만 값을 볼 수 있는 짧은 틈이 여전히 있다)

ㅇ -p 또는 --password 옵션 사용(비밀번호 값을 지정하지는 않음). 이런 경우 클라이언트
프로그램은 터미널에서 비밀번호를 물어본다:
shell> mysql -u user_name -p
Enter password: ********

클라이언트는 비밀번호를 칠 때 터미널에서 '*'  문자를 보여준다. 그러므로 다른 사용자가
비밀번호를 볼 수 없다. 다른 사용자가 볼 수 없으므로 명령행에서 비밀번호를 입력하는 것
보다 훨씬 더 안전하다. 그렇지만 이 방법은 비대화식의 스크립트로 클라이언트 프로그램을
사용하면 적절하지 않다.

ㅇ 설정 파일에 비밀번호 저장. 예를 들어 홈 디렉토리의 '.my.cnf' 파일에서 [client] 섹
션에 비밀번호를 지정할 수 있다.
[client]
password=your_pass

비밀번호를 '.my.cnf' 파일에 저장한다면 그 파일은 그룹이나 다른 사용자가 읽기/쓰기를
할 수 없도록 해야 한다. 파일의 퍼미션이 400 이나 600 인지 확인하자.

4.14.4 [옵션 파일] 참고.

ㅇ 비밀번호를 MYSQL_PWD 환경 변수에 저장할 수 있다. 그렇지만 이 방법은 정말로 위험하
며 사용해서는 안된다. 일부 ps 프로그램은 실행 프로세스의 환경변수를 보여주는 옵션이
있다; MYSQL_PWD에 설정을 하면 다른 사람들이 쉽게 비밀번호를 볼 수 있다. 이런 기능의 p
s가 없는 시스템일지라도 프로세스 환경변수를 검색할 수 있는 방법이 없다고 생각하는 것
은 현명하지 못하다.

이중에서 가장 안전한 방법은 클라이언트 프로그램이 비밀번호를 요구하거나 적절하게 보안
이 된 '.my.cnf' 파일에 비밀번호를 지정하는 것이다.

6.3 mysql에서 제공하는 권한

권한과 관련된 정보는 mysql 데이터베이스의(데이터베이스 이름이 mysql 임) user, db, hos
t, table_priv, columns_priv  테이블에 저장된다. mysql 서버는 시작할 때, 그리고 환경을
지정할 때(6.7 [권한 변경] 참고) 이 테이블의 내용을 읽어들인다.

mysql에서 제공하는 권한을 설정할 때 사용하는 이름은 아래와 같다.테이블의 컬럼 이름은
grant tables의 각 권한 및 권한이 적용되는 context와 연관되어 있다.


Privilege              Column         Context
(권한)          (컬럼)         (환경)
select         Select_priv     tables
insert         Insert_priv     tables
update         Update_priv     tables
delete         Delete_priv     tables
index          Index_priv      tables
alter          Alter_priv      tables
create         Create_priv     databases, tables or indexes
drop            Drop_priv       databases or tables
grant          Grant_priv      databases or tables
reload         Reload_priv     server administration
shutdown       Shutdown_priv   server administration
process        Process_priv    server administration
file            File_priv               file access on server


select, insert, update, delete 권한은 데이터베이스의 테이블에서 레코드에 대한 오퍼레
이션을 할 수 있도록 허용한다.

SELECT 문은 오직 실제로 테이블에서 줄(레코드)를 가져올 때만 select 권한이 필요하다.
서버의 데이터베이스에 접근 권한이 없는 경우라고 하더라도 특정한 SELECT  문은 사용할
수 있다. 예를 들면 간단한 계산을 위해 mysql 클라이언트를 사용할 수 있다:

mysql> SELECT 1+1;
mysql> SELECT PI()*2;

index(인덱스) 권한은 인덱스를 생성하거나 제거할 수 있다.

alter 권한은 ALTER TABLE 을 사용할 수 있도록 한다.

create  와 drop 권한은 새로운 데이터베이스와 테이블을 생성하거나 존재하는 데이터베이
스와 테이블을 제거할 수 있도록 허용한다.

사용자에게 mysql 데이터베이스의 drop 권한을 허용하면, 그 사용자는 mysql 접근권한 정보
가 저장된 데이터베이스를 없앨 수 있다는것!을 명심하자.


grant 권한은 사용자가 가지고 있는 권한을 다른 사용자가 가질 수 있도록 허용한다.

file 권한은 LOAD DATA INFILE and SELECT ... INTO OUTFILE  문을 이용하여 서버에 파일을
저장하고 읽을 수 있는 권한을 허용한다. 이러한 권한을 가진 사용자는 mysql 서버가 읽고
쓸 수 있는 파일을 읽고 쓸 수 있는 권한이 허용된다.

나머지 권한들은 관리자 오퍼레이션에 사용되며 mysqladmin 프로그램의 기능을 수행한다.
아래의 테이블은 각 관리자 권한에 따라 사용할 수 있는 mysqladmin 명령을 보여준다:

Privilege              Commands permitted to privilege holders
(권한)          (권한에 따라 허용되는 명령)
reload         reload, refresh, flush-privileges, flush-hosts, flush-logs, flush-tab
les
shutdown       shutdown
process        processlist, kill


reload 명령은 서버가 grant 테이블을 다시 읽어 들인다. refresh 명령은 모든 열린 테이블
을 닫으며 로그 파일을 열고 닫는다. flush-privileges 는 reload 명령과 동의어이다. 다른
flush-* 명령은 refresh 와 비슷한 기능을 수행한다. 그러나 범위에 제한이 있으며 어떤 경
우에는 더 선택할 만하다. 예를 들어 로그 파일만 닫고 다시 열고자 한다면 flush-logs 가
refresh보다 더 나은 선택이다.
(** flush의 옵션으로는 호스트, 로그 파일, 권한 설정, 테이블, status variables 설정 변
수가 있다. SQL 문에서 또는 mysqladmin 유틸리티를 사용하면 된다. **)

shutdown 명령은 서버를 셧다운한다. (** 이거 번역 맞아~~?? **)

processlist 명령은 서버에서 실행되고 있는 스레드에 대한 정보를 보여준다. kill 명령은
서버 스레드를 죽인다. 언제나 자신의 스레드는 보거나 죽일 수 있지만 다른 사용자에 의해
시작된 스레드는 프로세스 권한이 있어야 보거나 죽일 수 있다.

몇가지 권한은 조심스럽게 허용해야 한다:y:

ㅇ grant(허용) 권한은 사용자가 다른 사용자의 권한을 설정할 수 있도록 허용한다. 다른
권한과 grant 권한을 가진 두 사용자는 권한을 결합할 수 있다.
ㅇ file 권한은 서버에서 모든 사람이 읽기 가능한 파일을 읽는데 남용 될 수 있.... SELEC
T  문을 이용해 접근할 수 있는 내용...
The file privilege can be abused to read any world-readable file on the server into a
database table, the contents of which can then be accessed using SELECT.
(** 굳이 권한을 주지 않아도 이용할 수 있는 것은 권한을 주지 않는게 낫다는 말이겠지요
**)
ㅇ shutdown 권한은 다른 사용자에가 완전히 서비스를 사용하지 못하도록 남용될 수 있다.
ㅇ  process 권한은 비밀번호를 설정하고 바꾸는 질의를 포함해 현재 수행하고 있는 질의를
보는데 사용될 수 있다.
ㅇ mysql 데이터베이스에 대한 권한은 비밀번호와 다른 접근 권한 정보를 바꾸는 데 사용될
수 있다. (비밀번호가 암호화되어 저장되었다고 하더라도, 충분한 권한을 가진 악의있는 사
용자는 다른 비밀번호롤 바꿀 수 있다)

mysql 권한 시스템으로 다룰 수  없는 몇가지가 있다:
ㅇ 접근을 거부할 사용자를 명백하게 지정할 수 없다. 왜냐하면 사용자와 연결을 거부하는
것을 완전하게 연관시킬 수 없기 때문이다.
ㅇ 사용자가 테이터베이스에서 테이블을 만들고 지울 수 있는 권한을 가질 수 있지만 데이
터베이스 자체를 만들고 삭제할 수는 없도록 지정할 수 없다.
(** 그러니까 create 와 drop 권한을 주면 데이터베이스 자체에 대해 제어할 수 있지요. 그
안의 테이블만 만들고 지울 수 있도록 하지는 못한다는 말 **)

{{}}
6.4 권한 시스템 작동 방법

mysql 권한 시스템은 모든 사용자가 허용된 것만큼만 할 수 있도록 보증한다. mysql 서버에
연결할 때, 사용자 확인은 연결한 호스트와 사용자가 지정한 사용자 이름에 의해 결정된다.
시스템은 사용자 확인과 지정한 권한에 따라 권한을 허용한다.


mysql은 사용자를 확인하는데 호스트이름과 사용자 이름 둘다 사용한다. 왜냐면 인터넷에서
이름이 같다고 같은 사용자라고 생각할 수는 없기 때문이다. 예를 들어 whitehouse.gov에서
접속하는 사용자 bill 은 microsoft.com에서 접속하는 사용자 bill 과 같은 사람일 필요는
없다. mysql은 때론 같은 이름을 가지고 있더라도 호스트를 이용해 사용자를 구별한다 : wh
itehouse.gov에서 접속하는 bill에게 특정한 권한을 허용할 수 있고 microsoft.com에서 접
속하는 bill에게 다른 권한을 허용할 수 있다.

mysql의 접근 제어는 두가지 단계가 있다:

단계 1: 서버에서 사용자가 연결할 수 있는지 없는지 판단

단계 2 (서버에 사용자가 연결이 허용되었을 경우) : 사용자가 수행하려는 명령에 대해 충
분한 권한이 있는지 각 요청마다 서버에서 판단.예를 들면, 데이터베이스의 테이블에서 sel
ect rows를 할때, 또는 데이터베이스에서 테이블을 제거할 때 서버에서 테이블에 대한 sele
ct 권한이 있는지 데이터베이스에 대한 제거 권한이 있는지 확인을 한다.

 

서버는 접근 제어의 각 두 단계에서 mysql 데이터베이스의 user, db, host 테이블을 이용한
다.grant 테이블의 필드는 아래와 같다:

Table name     user            db              host
Scope fields   Host            Host            Host
(필드 범위)     User            Db              Db
                Password                User
Privilege fields      Select_priv     Select_priv     Select_priv
(권한 필드)     Insert_priv     Insert_priv     Insert_priv
                Update_priv     Update_priv     Update_priv
                Delete_priv     Delete_priv     Delete_priv
                Index_priv      Index_priv      Index_priv
                Alter_priv      Alter_priv      Alter_priv
                Create_priv     Create_priv     Create_priv
                Drop_priv       Drop_priv       Drop_priv
                Grant_priv      Grant_priv      Grant_priv
                Reload_priv            
                Shutdown_priv          
                Process_priv           
                File_priv              


접권 제어의 두번째 단계를 위해(요청 인증), 요청이 테이블에 관계된 것이라면 추가적으로
tables_priv 와 columns_priv 테이블을 참고한다. 이 테이블의 필드는 다음과 같다:

Table name     tables_priv     columns_priv
Scope fields   Host            Host
                Db              Db
                User            User
                Table_name      Table_name
                                Column_name
Privilege fields      Table_priv      Type
                Column_priv    
Other fields   Timestamp       Timestamp
                Grantor

 


각 승인(grant) 테이블은 필드 범위와 권한 필드로 구성되어 있다.

필드 범위는 테이블에서 각 엔트리의 범위를 결정한다. 다시 말하면 엔트리가 적용되는 con
text(환경, 배경)이다. 예를 들면, Host 와 User 값이 'thomas.loc.gov' 와 'bob' 인 user
테이블 엔트리는 thomas.loc.gov 호스트에서 bob이 연결을 할때 서버에서 인증을 하는데 사
용된다.비슷하게 Host, User, db 필드값이  'thomas.loc.gov', 'bob', 'reports' 인 db 테
이블 엔트리는 thomas.loc.gov 호스트에서 bob 이 reports 데이터베이스에 접근할 때 사용
된다. tables_priv 와 columns_priv 테이블은 테이블이나 각 엔트리가 적용될 수 있는 테이
블/컬럼 조합을 가리키는 범위 필드를 포함하고 있다.

접권 체크를 하기 위해, HOst 값 비교는 대소문자를 구별하지 않는다. User, Password, Db,
Table_name 값은 대소문자를 구별한다. mysql 3.22.12 와  이후 버전에서 Column_name 값은
대소문자를 구별하지 않는다. (3.22.11에서는 대소문자 구별함)

권한 필드는 테이블 엔트리에 승인되는 권한을 가리키며 이는 수행할 수 있는 오페레이션이
다. 서버는 사용자의 권한을 완벽하게 설정하기 위해 다양한 승인(grant) 테이블의 정보를
조합한다. 여기에 사용하는 규칙은 6.6 [Request access]를 참고하자.

범위 필드는 문자열이며 다음과 같이 정의되었다; 기본 값은 빈 문자열이다:

Field name     Type   
Host            CHAR(60)       
User            CHAR(16)       
Password                CHAR(16)       
Db              CHAR(64)      (CHAR(60) for the tables_priv and columns_priv tables)

 

user, db, host 테이블에서 모든 권한 필드는 ENUM('N','Y')로 정의되어 있다. -- 각각은
'N' 나 'Y'의 값을 가지며 기본값은 'N' 이다.
(** ENUM 타입은 목록 값중 오직 하나의 값만 가진다.필드 타입 참조 **)

tables_priv 와 columns_priv 테이블에서 권한 필드는 SET 필드로 정의된다:
(** SET 타입은 목록 값중에 0이나 1개 이상의 값을 가진다 **)

Table name     Field name     Possible set elements
tables_priv     Table_priv      'Select', 'Insert', 'Update',
                                'Delete', 'Create', 'Drop', 'Grant',
                                'References', 'Index', 'Alter'
tables_priv     Column_priv     'Select', 'Insert', 'Update',
                                'References'
columns_priv    Type            'Select', 'Insert', 'Update',
                                'References'

간단하게 말해서 서버는 승인(grant) 테이블을 다음과 같이 사용한다:

ㅇ user 테이블의 scope(범위) 필드는 들어오는 연결에 대해 허용할 것인지 거부할 것인지
를 결정한다. 허용된 연결에 대하여, 권한 필드는 사용자의 전체적인 (superuser) 권한을
가리킨다.

ㅇ db 와 host 테이블은 함께 사용된다:
        - db 테이블의 범위 필드는 어떤 호스트에서 어떤 데이터베이스에 대해 어떤 사용
자가 접근할 수 있는지 결정한다. 권한 필드는 어떤 오퍼레이션이 허용되었는지를 결정한
다.
        - host 테이블은 db 테이블의 엔트리를 여러개의 호스트에 적용하려고 할 때 db 테
이블의 확장을 위해 사용한다.예를 들어, 사용자가 현재 네트웍의 여러 호스트에서 데이터
베이스를 사용할 수 있도록 하려면,사용자의 "db" 테이블 엔트리에 Host 값을 비워두고, "h
ost" 테이블에 각 호스트의 엔트리를 넣으면 된다.이러한 절차는 6,6 [Request access]에
자세하게 나와 있다.

ㅇ tables_priv 와 columns_priv 테이블은 db 테이블과 비슷하다. 그렇지만 더 세부적으로
지정할 수 있다: 이 테이블들은 데이터베이스 단계에서 더 나아가 테이블과 컬럼 단계에 적
용할 수 있다.

관리 권한(reload, shutdown,기타..)은 오직 user 테이블에서만 지정을 할 수 있다는 것을
기억하자! 왜냐면 관리자 오퍼레이션은 서버 자체에 대한 오퍼레이션이며 특정한 데이터베
이스를 지정하는 것이 아니다. 그러므로 이러한 권한은 다른 승인(grant) 테이블에 있을 필
요가 없다.실제로, 오직 user 테이블만이 관리자 오퍼레이션을 수행할 수 있는지 없는지를
결정할 때 참고가 된다.

파일(file) 권한도 마찬가지로 user 테이블에서만 지정한다.위와 같은 관리 권한은 아니다.
그렇지만 서버 호스트에서 파일을 읽거나 쓸 수 있는 권한은 접근하고 있는 데이터베이스와
무관한 것이다.

mysqld 서버는 시작할 때 승인(grant) 테이블을 한번 읽는다. 승인 테이블을 변경하고 효과
를 발휘하려면 6.7 [Privilege changes]를 참고하자.

승인 테이블의 내용을 수정했을 때 원하는대로 권한이 설정되었는지 확인하는 것은 좋은 생
각이다. 유용한 진단 프로그램은 mysqlaccess 스크립트로서 Yves CArlier 가 mysql distrib
ution 으로 제공하고 있다. 어떻게 작동하고 있는지 확인하기 위해 mysqlaccess 에 --help
옵션을 주어 실행해보자. 물론 6.11 [Access denied] 와 6.12 [Security]를 참고하자.


mysqlaccess는 오직 user, db, host 테이블만 점검한다. 테이블이나 컬럼 단계의 권한까지
는 점검하지 않는다는 것을 기억하자.

6.5 접근 제어, 단계 1 : 연결 확인(인증)

mysql 서버에 접속하려고 할 때 서버는 사용자 확인과 비밀번호를 통해 접속을 허용하거나
거부한다. 사용자 확인이 안되면 서버는 접속을 완전히 거부한다. 사용자 확인이 되면 서버
는 연결을 받아들이고 2번째 단계로 들어가며 요청을 기다린다.

사용자 확인은 두가지 정보에 기반하고 있다:

ㅇ 접속하는 호스트
ㅇ mysql 사용자 이름

사용자 확인은 user 테이블의 세가지 범위 필드(Host, User, Password)를 사용하여 수행된
다. 서버는 user 테이블 엔트리의 호스트이름과 사용자 이름이 맞으며, 비밀번호가 정확할
때만 접속을 받아들인다.

아래와 같이 user 테이블의 범위 필드값을 지정할 수 있다:

ㅇ Host 값은 호스트 이름이나 IP 숫자 또는 로컬 호스트를 가리키는 'localhost' 가 될 것
이다.
ㅇ Host 필드에서 '%' 와 '_' 의 와일드카드 문자를 사용할 수 있다.
ㅇ '%'의 Host 값은 모든 호스트 이름을 나타낸다. 공백의 호스트 값은 '%'와 같다. 특정한
호스트에 대한 이러한 값은 당신의 서버에 연결할 수 있다는 것을 참고하자.
ㅇ 와일드카드 문자는 User 필드에는 허용되지 않는다. 그렇지만 모든 유저에 해당하는 공
백으로 둘 수 있다. 연결을 하려는 목록에 공백 사용자 이름이 있다면 클라이언트에서 실제
로 지정한 이름 대신에 그 사용자는 익명 사용자, 이름이 없는 사용자로서 간주된다.
ㅇ Password 필드는 공백으로 될 수 있다.이것은 아무런 비밀번호나 사용할 수 있다는 것을
의미하는 것은 아니며 사용자는 비밀번호를 지정하지 않고 연결을 해야 한다는 의미이다.

아래의 테이블은 연결 요청에 적용하는 "user" 테이블 목록의 Host, User 값이 어떻게 조합
되는지를 보여주는 예제이다:

호스트값/사용자 값 : 목록에 해당하는 연결
'thomas.loc.gov'/'fred' : thomas.loc.gov 에서 연결하는 fred
'thomas.loc.gov'/'' : thomas.loc.gov 에서 연결하는 모든 사용자
'%'/'fred' : 모든 호스트에서 연결하는 fred
'%'/'' : 모든 호스트에서 연결하는 모든 사용자
'%.loc.gov'/'fred' : loc.gov 도메인의 모든 호스트에서 연결하는 fred
'x.y.%'/'fred' : x.y.net, x.y.com, x.y.edu 등에서 접속하는 fred (이것은 아마도 유용하
지 않을 것이다)
'144.155.166.177'/'fred' : 144.155.166.177의 IP 주소에서 접속하는 fred
'144.155.166.%'/'fred' : 144.155.166 클래스 C 서브넷의 모든 호스트에서 접속하는 fred


Host 필드에서 IP에 와일드 카드를 사용할 수 있기 때문에(예를 들어 '144.155.166.%' 는
서브넷의 모든 호스트에 적용된다) 144.155.166.somewhere 와 같은 호스트 이름을 이용하여
부당하게 이용할 가능성이 생길 수 있다. 이러한 것을 막기 위해 mysql은 숫자와 도트(.)으
로 시작하는 호스트이름은 허용하지 않는다. 1.2.foo.com 과 같은 호스트라면 이러한 호스
트이름은 승인(grant) 테이블의 Host 컬럼과 매치되지 않는다. IP 숫자만이 IP 와일드 카드
값과 매치시킬 수 있다.

만약 한개 이상의 user table 목록이 있다면 서버는 어떻게 user table을 선택할까? 이런
경우에는 user table의 정렬 순서에 따라 해결을 하며 , 정열은 서버가 시작할때 수행이 된
다. user table이 다음과 같다고 가정해보자:


+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-

 

서버가 테이블을 읽을 때, 먼저 특정하게 지정된 값이 있는 호스트부터 목록을 정열한다.
(Host 컬럼에서 '%'는 "모든 호스트"를 의미하여 최소한도로 지정하는 것이다) 목록에서 호
스트값이 같으면 먼저 특정하게 지정된 사용자가 있는 것부터 정열한다.(공백으로 되어 있
는 User 값은 "모든 사용자"를 의미하여 최소한도로 지정하는 것이다.) 이렇게 하면 정열된
user 테이블은 다음과 같다:

 

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-


정열된 순서에 따라 매칭 알고리즘이 적용되며 먼저 매칭되는 것을 사용한다. localhost에
서 jeffrey가 연결을 하려할때, Host 컬럼에서 'localhost' 목록이 먼저 매칭된다. 물론 사
용자 이름이 공백인 목록은 연결하는 호스트네임과 사용자 이름에 매칭된다. ('%'/'jeffrey
' 목록 또한 매칭이 된다. 그러나 테이블에서 처음으로 매칭되는 것은 아니다.)


다른 예제가 있다. user 테이블이 다음과 같다고 가정해보자:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| thomas.loc.gov |          | ...
+----------------+----------+-


정열된 테이블은 다음과 같다:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| thomas.loc.gov |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

첫번째로 thomas.loc.gov에서 jeffrey가 연결하는 것이 매칭되며, whitehouse.gov 에서 jef
frey가 연결하는 거은 두번째로 매칭이 된다.

서버에 연결할 때 문제가 생기면, user 테이블을 출력하여 어떤 것이 먼저 매칭되는지 직접
정열을 하면 된다.


6.6 접근 제어, 2단계 : 요청 인증

{{}}연결되었다면 서버는 2단계로 들어간다. 연결이 성사되었을 때 각 요구에 대해 사용자가 수
행하려는 연산의 유형에 기반하여 서버는 사용자가 충분한 권한을 가지고 있는지 점검한다.
여기서 승인 테이블의 권한 필드가 작동한다. 권한은 user, db, host, table_priv, columns
_priv 테이블의 정보를 사용한다. GRANT 와 REVOKE 명령을 이용하여 권한 테이블을 다룰 수
있다. 7.25 [GRANT] 참고. (이전에 보았던 각 권한 테이블의 필드 목록을 참고하는 것이 도
움이 될 것이다; 6.4[Privilege] 참고.)

user 테이블의 승인 권한은 사용자에게 전체적인 기반을 제공하며 현재의 데이터가 어떤 것
인지와는 상관이 없다. 예를 들어, user 테이블에서 사용자에게 delete 권한을 승인했다면
서버 호스트에서 어떤 데이터베이스의 레코드라도 삭제할 수 있다! 다르게 말해서 user 테
이블 권한은 슈퍼유저 권한이며, 슈퍼유저(서버나 데이터베이스 관리자 등)에게만 user 테
이블에 대한 권한을 승인하는 것이 좋다. 다른 사용자에게는 user 테이블에서 권한을 'N'로
설정하고, db와 host 테이블을 사용하여 특정 데이터베이스에 기반한 권한승인을 하는게 좋
다.

db 와 host 테이블은 특정 데이터베이스의 권한을 승인한다. 각 테이블의 Host 와 Db 필드
에서 와일드카드 문자 '%' 와 '_' 를 사용할 수 있으며 값이 공백이면 필드 범위(scope fie
lds)에서 모든 값을 허용한다. '%' Host 값은 "모든 호스트"를 의미한다. db 테이블에서 Ho
st 값이 공백이면 "host 테이블에서 더 자세한 정보를 문의하라"는 의미이다. A '%' or bla
nk Db value in the host table means or "any database." (** or의 뜻이 무엇인지 모르겠
네요. host 테이블에서 Db 의 값이 '%' 또는 공백이면 "모든 데이터베이스"를 의미한다는
말 같은데요 **) User 값이 공백이면 익명 사용자로 간주된다.

서버가 시작할 때 db 와 host 테이블을 읽고 정열을 한다.(동시에 user 테이블을 읽는다.)
db 테이블은 Host, Db, User 순으로 필드 범위를 정열하며 host 테이블은 Host, Db 순으로
필드 범위를 정열한다. user 테이블과 같이 특정하게 지정되어 있는 값이 먼저 정열되고 최
소한도로 지정된 값이 나중에 정열된다. 서버에서 매칭되는 목록을 찾을때, 가장 먼저 발견
한 것을 사용한다.

 tables_priv 와 columns_priv 테이블은 특정한 테이블과 컬럼에 관련된 권한을 승인한다.d
b와 host 테이블의 Host 필드와 같이 와일드카드를 Host 필드에서 사용할 수 있다. 그렇지
만 Db, Table_name, Column_name 필드에서는 와일드카드나 공백값을 사용할 수 없다.

Host 테이블에서만 와일드카드를 사용할 수 있지만 tables_priv 와 columns_priv 테이블은
db 테이블과 비슷하게 정열이 되며 정열은 간단하다.

요청 인증 과정은 아래에서 설명한다. 접근-점검 소스 코드에 친숙하다면, 여기서 설명하는
것은 코드에서 사용된 알고리즘과는 약간 다르다는 것을 알 수 있다.여기서의 설명은 코드
가 실제로 작동하는 방식과 동일하다. 단지 설명을 간단하게 하는데서 차이가 있는 것이다.

관리자 요청에 대해서(shutdown, reload 등) 서버는 단지 user 테이블만 체크를 한다. 왜냐
면 user 테이블에서만 관리자 권한을 지정하기 때문이다. 목록에서 요청된 연산을 허용하면
접근이 허용되며 아닌 경우에는 접근이 거부된다.예를 들어, mysqladmin shutdown을 실행하
고자 하는데 user 테이블 목록에서는 사용자에게 shutdown 권한을 승인하지 않으면, db나 h
ost 테이블을 체크하지 않더라도 접근이 거부된다. (이러한 테이블에는 Shutdown_priv 컬럼
이 없기 때문에 이렇게 할 필요도 없다)

데이터베이스와 관련된 요청에 대해(insert, update 등) 서버는 먼저 user 테이블 목록에서
사용자의 전체(슈퍼유저) 권한을 점검한다. 목록에서 요청한 연산을 허용하면 접근이 승인
된다.

user 테이블에서 전체적인 권한이 불충분하면, 서버는 db 와 host 테이블을 점검하여 데이
터베이스에 관련된 권한을 결정한다:

1. 서버는 db 테이블에서 매칭되는 Host, Db, User 필드를 찾는다. 연결하려는 사용자의 호
스트 이름과 Mysql 사용자 이름이 Host 와 User에 매칭되다. 사용자가 접근하기 원하는 데
이터베이스는 Db 필드에 매칭된다. 적합한 Host 와 User 목록이 없으면 접근은 거부된다.

2. 매칭되는 db 테이블 목록이 있고 Host 필드가 공백이 아니면, 목록은 사용자의 데이터베
이스 관련 권한을 정의한다.


3. 매칭되는 db 테이블 목록의 Host 필드가 공백이면, host 테이블에서 어떤 호스트가 데이
터베이스에 접근할 수 있는지 판단한다는 것을 의미한다. 이런 경우, 더 자세한 정보를 위
해 host 테이블에서 매칭되는 Host 와 Db 필드를 찾는다. host 테이블에 매칭되는 목록이
없으면 접근은 거부된다. 매칭되는 목록이 있으면 사용자의 데이터베이스 관련 권한은 db
와 host 테이블 목록에서 권한을 intersection 하여 결정된다.(** insertection은 교집합을
생각하면 되지요. and 조건 **) 다시 말해서, db와 host 테이블 둘 다 'Y'로 되어있을 때
권한이 설정된다.이러한 방법으로 db 테이블에서 일반적인 권한을 승인할 수 있으며, 그러
고나서 host 테이블 목록을 사용해 host를 기반으로 하여 선택적으로 권한을 제한할 수 있
다.)

db 와 host 테이블 목록을 이용해 데이터베이스와 관련된 권한 승인을 결정한 후, 서버는
이러한 정보를 user 테이블에서 승인한 전체적인 권한에 추가한다. 그 결과가 요청한 연산
을 허용하면 접근이 허용된다. 다른 방법으로, 서버는 tables_priv 와 columns_priv 테이블
에서 사용자의 테이블과 컬럼 권한을 점검하고 사용자의 권한에 추가한다. 그 결과에 따라
접근이 허용되거나 거부된다.

왜 서버에서 전체적인 사용자 엔트리 권한에 데이터베이스, 테이블, 컬럼에 관련된 권한을
추가하는지가 명확하지 않다.... 이런 경우 사용자 권한은 초기에 요청된 연산에 대하여 불
충분하다... (It may not be apparent why the server adds the database-, table- and col
umn-specific privileges to the global user entry privileges for those cases in which
the user privileges are initially found to be insufficient for the requested operatio
n.) 요청은 한가지 유형 이상의 권한이 필요하기 때문이다. 예를 들어, INSERT ... SELECT
문을 수행할 때 insert 와 select 권한 둘 다 필요하다. 사용자의 권한은 user 테이블에서
한가지 권한을 승인하고 db 테이블 엔트리에서 다른 권한을 승인할 것이다. 이런 경우, 사
용자는 이러한 요청을 수행하기 위해 필요한 권한을 가지고 있다. 그렇지만 서버는 자체적
으로 다른 테이블에 대해서는 .....(In this case, you have the necessary privileges to
perform the request, but the server cannot tell that from either table by itself;) ;
두 엔트리에 의해 승인된 권한이 조합되어야 한다.

host 테이블은 "안전한" 서버 목록을 유지하는데 사용할 수 있다. TcX에서는, host 테이블
에는 지역 네트웍의 모든 시스템이 포함되어 있다. 여기서는 모든 권한이 허용된다.

안전하지 않는 호스트를 가리키기 위해 host 테이블을 사용할 수 있다. 안전하다고 생각되
지 않는 공개 지역에 위치한 public.your.domain 시스템이 있다고 가정해보자. 사용자는 사
용자 네트웍의 모든 호스트에 접근할 수 있으며, host 테이블 엔트리가 다음과 같은 시스템
만 제외한다 :

+--------------------+----+-
| Host               | Db | ...
+--------------------+----+-
| public.your.domain | %  | ... (all privileges set to 'N')
| %.your.domain      | %  | ... (all privileges set to 'Y')
+--------------------+----+-

당연히 접근 권한이 원하는대로 되어 있는지 언제나 승인 테이블에서 목록을 테스팅해야 한
다. (예를 들어 mysqlaccess 를 사용)

 

6.7 권한 변경시 적용 방법


mysqld 가 시작할 때, 모든 승인 테이블 내용이 메모리로 올라가고 이때부터 유효하게 된
다.

GRANT, REVOKE, SET PASSWORD 를 이용해 승인 테이블에 변경을 하면 바로 서버에서 인식을
한다.

권한 테이블을 직접 변경했다면(INSERT, UPDATE 등을 사용하여), 서버에서 승인 테이블을
재가동하도록 하기 위해 FLUSH PRIVIEGES 문이나 mysqladmin flush-privileges 를 실행해야
한다.그렇게 하지 않으면 서버를 다시 시작하기 전까지 변경된 권한이 적용되지 않는다.

서버에서 권한 테이블이 변경되었다는 것을 감지했을 때, 이미 존재하던 클라이언트 연결은
다음과 같이 영향을 받는다:

1. 테이블과 컬럼 권한 변경은 클라이언트의 다음 요청부터 적용된다.
2. 데이터베이스 권한 변경은 다음의 USE db_name 명령부터 적용된다.
3. 전체적인 권한과 비밀번호 변경은 클라이언트가 다음에 연결할 때부터 적용된다.
{{}}

6.8 초기 mysql 권한설정

mysql을 설치하고 나서, mysql_install_db 스크립트를 실행해서 초기 접근 권한을 설정해야
한다. 4.7.1 [Quick install] 참고. mysql_install_db 스크립트는 mysqld 서버를 시작하고,
다음과 같이 승인 테이블의 권한을 초기화한다:

- mysql root 사용자는 슈퍼유저이며 모든 것을 할 수 있다. 로컬 호스트에서만 연결할 수
있다.
주의 : 처음에 root 비밀번호는 비어있다. 그래서 누구나 비밀번호없이 root로 연결할 수있
고 모든 권한을 승인받는다.

- 익명 사용자는 'test' 나 'test_' 로 시작하는 데이터베이스에 대한 모든 권한을 승인받
는다. 모든 사용자가 로컬 호스트에서 연결할 수 있으며 익명 사용자로 간주된다.

- 다른 권한은 거부된다. 예를 들어 일반 사용자는 mysqladmin shutdown 이나 mysqladmin p
rocesslist 를 사용할 수 없다.


설치했을 때 초기 권한이 폭넓게  설정되어 있기 때문에 가장 먼저 mysql root 사용자의 비
밀번호를 설정해야 한다. 다음과 같이 설정하면 된다. (PASSWORD() 함수를 이용해 비밀번호
를 설정해야 한다!):

shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
           WHERE user='root';
mysql> FLUSH PRIVILEGES;

or

shell> mysqladmin -u root password new_password
(** PASSWORD() 라는 함수를 사용하지 않아도 되므로 편리함. 또한 SQL문에서 grant 명령을
이용해 설정할 수도 있지요 **)

첫번째 방법을 사용하면 직접 user 테이블의 비밀번호를 업데이트한다. 이경우 서버가 다시
승인 테이블을 읽도록 해야 한다.(FLUSH PRIVILEGES 사용). 왜냐하면 다른 방법으로는 변경
사항을 알릴 수 없기 때문이다.

(** 승인 테이블을 다시 읽지 않아서 이전에 설정했던 비밀번호가 제대로 안되는 경우가 있
을 것입니다. 꼭 기억하고 있어야해요 **)

root 비밀번호가 설정되었으면 서버에 root로 접속할때마다 비밀번호를 명시해야 한다.

추가로 셋업을 하거나 테스트할 때는 비밀번호를 설정할 필요가 없기 때문에 root 비밀번호
를 빈값으로 남겨두고 싶을 것이다. 그렇지만 실제 작업을 하기 전에는 반드시 비밀번호를
설정했는지 확인해야 한다.

기본권한을 어떻게 설정하는지 mysql_install_db 스크립트를 살펴보자. 다른 사용자에게 권
한을 어떻게 설정할지 이것을 기본으로 사용할 수 있다.

위에서 설명한 것과 다르게 초기 권한을 설정하기 원하면, mysql_install_db 스크립트를 실
행하기 전에 수정하면 된다.

완전하게 승인 테이블을 다시 만들기 위해 mysql 데이터베이스를 포함하는 디렉토리의 '*IS
M' 과 '*.ISD' 파일을 제거해야 한다. (이 디렉토리는 database 디렉토리에서 'mysq''이라
는 이름이 붙어있다. mysqld --help 해서 database 디렉토리의 목록을 볼 수 있다.) 원하는
대로 권한을 수정한 후 mysql_install_db 스크립트를 실행하자.


6.9 mysql에 새로운 사용자 권한 추가하기

두가지 방법으로 사용자를 추가할 수 있다 : GRANT 문 사용 또는 mysql 승인 테이블 직접
조작. GRANT 문을 사용하는 것이 더 선호되는 방법이다.

아래의 예제는 새로운 사용자를 설정하기 위해 어떻게 mysql 클라이언트를 사용하는지 보여
준다. 이 예제는 이전에 설명했던것과 같이 기본값에 따라 권한을 설정하는 것으로 가정한
다. 이것은 설정을 바꾸기 위해 mysqld가 실행되고 있는 같은 시스템에 있어야 한다는 것을
말한다. (**초기값은 localhost에서만 접속 가능하므로**) 또한 mysql root 사용자로 접속
해야 하고 root 사용자는 mysql 데이터베이스에 대한 insert 권한과 reload 관리자 권한이
있어야 한다. root 사용자의 비밀번호를 바꾸었으면, 아래와 같이 mysql 명령행 상태에서
비밀번호를 명시해야 한다.

GRANT 문을 이용해 새로운 사용자를 추가할 수 있다:

shell> mysql --user=root mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
           IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%"
           IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
mysql> GRANT USAGE ON *.* TO dummy@localhost;

위 GRANT 문에서는 세 명의 사용자를 설정한다:

monty : 어느 곳에서든 서버에 연결할 수 있는 완전한 슈퍼유저이지만 비밀번호를 사용해야
한다. 우리는 monty@localhostmonty@"%"를 사용한 GRANT 문에 대해서 반드시 논의를 해
야 한다. localhost 목록을 추가하지 않으면, mysql_install_db 에 의해 생성된 localhost
의 익명 사용자 목록(등록?)이 로컬 호스트에서 접속할때 우선권을 갖는다. 왜냐하면 지정
된 Host 필드 값이 있으며 정열 순서에서 먼저 오기 때문이다. (** 승인 테이블의 정열 순
서가 특정한 Host를 지정한 것부터 시작하는 것을 기억하자.

admin : 비밀번호 없이 localhost에서 접속할 수 있으며 reload와 process 관리자 권한을
승인받은 사용자. 이경우 사용자가 mysqladmin processlist 뿐만 아니라 mysqladmin reloa
d, mysqladmin refresh, mysqladmin flush-* 명령을 실행할 수 있다.데이터베이스와 관련된
권한은 승인되지 않았다. 이것은 추가적인 GRANT 문을 사용해 나중에 승인할 수 있다.

dummy : 비밀번호없이 연결할 수 있지만 오직 localhost에서만 연결 가능한 사용자. 권한
유형(privilege type)이 USAGE 이기 때문에 전체적인 권한이 'N'로 설정되어 있다. USAGE
는 아무런 권한도 설정하지 않는다. 나중에 데이터베이스와 관련된 권한을 승인할 수 있다.

또한 동일한 사용자 접근 정보를 INSERT 문을 통해 직접 추가할 수 있으며 이경우에는 서버
가 승인 테이블을 다시 읽도록 알려주어야 한다.(**FLUSH PRIVILEGES 사용**)

shell> mysql --user=root mysql
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('something'),
                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),
                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user SET Host='localhost',User='admin',
                 Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
                        VALUES('localhost','dummy',");
mysql> FLUSH PRIVILEGES;

mysql 버전에 따라 위에서 'Y' 값이 다를 수 있다는 것을 기억하자. 3.22.11 버전 이후에서
사용할 수 있는 확장된 INSERT 문은 여기서 admin 사용자에게 사용되었다.

슈퍼유저를 설정하기 위해 권한필드를 'Y'로 한 user 테이블 목록만 만들면 된다는 것을 기
억하자. db 나 host 테이블 목록은 필요없다. (** 관리자 권한은 db나 host 테이블과는 전
혀 관련이 없다. db는 접속할 수 있는 데이터베이스에 대해 상세하게 설정하고 host 테이블
은 db테이블을 좀 더 정교하게 설정하기 위해 필요한 것이다. 관리자 권한은 오직 user 테
이블만 관련되어있다 **)

마지막 INSERT 문(dummy 사용자)에서는 user 테이블의 권한 컬럼이 명확하게 설정되지 않았
다. 왜냐면 이 컬럼의 기본값은 'N'로 되어 있기 때문이다.

다음의 예제에서는 custom 이라는 사용자를 추가한다. custom은 localhost, server.domain,
whitehouse.gov에서 접속할 수 있다. localhost에서는 bankaccount 데이터베이스에만 접속
할 수 있으며 whitehouse.gov에서는 expenses 데이터베이스에, 모든 세 호스트상에서는 cus
tomer 데이터베이스에 접속하길 원한다. 모든 세 호스트상에서 stupid라는 비밀번호를 사용
하길 원한다.

GRANT 문을 이용 이러한 사용자 권한을 설정하기 위해 다음의 명령을 실행하자:

shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON bankaccount.*
           TO custom@localhost
           IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON expenses.*
           TO custom@whitehouse.gov
           IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON customer.*
           TO custom@'%'
           IDENTIFIED BY 'stupid';

승인 테이블을 직접 수정해 사용자 권한을 설정하려면 다음의 명령을 사용하자. (마지막에
FLUSH PRIVILEGES 를 사용해야 한다는 것을 기억하자):

shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES('localhost','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
       VALUES('server.domain','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
       VALUES('whitehouse.gov','custom',PASSWORD('stupid'));
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       ('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       ('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;
~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~

처음의 세가지 INSERT 문은 custom 사용자가 비밀번호를 사용하여 다양한 호스트에서 접속
할 수 있도록 user 테이블 목록을 추가한다. 그렇지만 그에게 어떠한 퍼미션도 승인하지 않
는다. (모든 권한은 기본값으로 'N' 이다) 다음의 세가지 INSERT 문은 적절한 호스트에서
접속을 할 때, custom 에게 bankaccount, expenses, customer 데이터베이스에 대한 권한을
승인하는 db 테이블 목록을 추가한다. 일반적으로 승인 테이블을 직접 수정하였으면, 변경
된 권한을 적용하기 위해 서버가 승인 테이블을 다시 읽도록 해 주어야 한다.

특정한 사용자가 특정한 도메인의 시스템에서 접속할 수 있도록 설정하고자 한다면, 다음과
같이 GRANT 문을 설정할 수 있다:

mysql> GRANT ...
           ON *.*
           TO myusername@"%.mydomainname.com"
           IDENTIFIED BY 'mypassword';

승인 테이블을 직접 수정하려면 다음과 같이 한다:

mysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername',
           PASSWORD('mypassword'),...);
mysql> FLUSH PRIVILEGES;
~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~

승인 테이블을 다루기 위해 xmysqladmin, mysql_webadmin, xmysql 프로그램을 사용할 수 있
다. http://www.mysql.com/Contrib 에서 이러한 유틸리티를 찾을 수 있다.


6.10 비밀번호 설정 방법

앞의 예제는 중요한 원칙을 보여준다 : INSERT 나 UPDATE 문에서 공백이 아닌 비밀번호를
저장할 때 반드시 암호화하기 위해 PASSWORD() 함수를 사용해야 한다!! user 테이블은 비밀
번호를 플레인텍스트(**일반 텍스트 파일**)가 아니라 암호화된 형태로 저장하기 때문이다.
이러한 사실을 잊어버리면 다음과 같이 비밀번호를 설정하려고 할 것이다:

shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES('%','jeffrey','bLa81m0');
mysql> FLUSH PRIVILEGES;

플레인텍스트 값 'bLa81m0' 은 user 테이블에 비밀번호로 저장이 된다.jeffrey라는 사용자
가 이 비밀번호를 사용해 서버에 연결하려고 할 때 mysql 클라이언트를 이 비밀번호를 암호
화해서 그 결과를 서버로 보낸다. 서버는 암호화된 비밀번호('bLa81m0'이 아니다)를 user
테이블의 비밀번호(플레인텍스트 'bLa81m0' 값이다)와 비교한다. 비교는 실패하고 서버는
연결을 거부한다:

shell> mysql -u jeffrey -pbLa81m0 test
Access denied

비밀번호는 user 테이블에 입력될 때 반드시 암호화되어야 하기 때문에, INSERT 문은 다음
과 같이 사용해야 한다:

mysql> INSERT INTO user (Host,User,Password)
       VALUES('%','jeffrey',PASSWORD('bLa81m0'));

또한 SET PASSWORD 문을 사용할 때도 PASSWORD() 함수를 사용해야 한다:

mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('bLa81m0');

참고 : PASSWORD() 함수는 비밀번호 암호화를 수행한다. 그렇지만 유닉스에서 비밀번호를
암호화하는 방법과는 다르다. 유닉스 비밀번호와 mysql 비밀번호가 동일할 때 PASSWORD()
가 유닉스 비밀번호 파일(** /etc/passwd 파일 **)에 암호화되어 저장된 값과 같다고 생각
하면 안 된다.

GRANT ... IDENTIFIED BY 문이나 mysqladmin password 명령을 사용해 비밀번호를 설정하면
PASSWORD() 함수는 필요없다. 둘다 비밀번호를 암호화해서 저장한다:

mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'bLa81m0';
shell> mysqladmin -u jeffrey password bLa81m0

(** 당근, GRANT 문이나 mysqladmin password 명령을 사용하는게 편하겠지요? mysql의 암호
화 알고리즘이 유닉스와 다르듯 유닉스 계정과 mysql의 사용자는 전혀 다르다는 것도 다시
한번 기억하고 있어야 합니다.**)

 

6.11 접근 거부 에러가 나는 이유

mysql 서버에 연결하려 할 때 접근 거부 에러가 나면, 아래에서 설명하는 것에 따라 해결
방법을 찾을 수 있다:

- 초기 승인 테이블 내용을 설정하기 위해 mysql을 설치한 후 mysql_install_db 스크립트를
실행하였는가? 실행하지 않았다면 스크립트를 실행하자. 6.8 [Default privileges] 참고.
다음 명령을 이용해 초기 권한을 시험해 볼 수 있다:

        shell> mysql -u root test

에러없이 서버에 접속할 수 있을 것이다. mysql 데이터베이스 디렉토리에 'user.ISD' 파일
이 있는지 확인해보아야 한다. (일반적으로 'mysql 설치 디렉토리/var/mysql/user.IDS' 이
다)

- 설치를 새로하고 난후 , 서버에 연결하고 사용자와 접근 권한을 설정해야 한다:

        shell> mysql -u root mysql

초기에 mysql root 사용자만 비밀번호가 없기 때문에 서버에 연결할 수 있다. 보안문제가
있기 때문에, 다른 mysql 사용자를 설정하기 전에 먼저 root의 비밀번호를 설정해야 한다.
root로 접속하려하는데 다음의 에러가 났다고 가정하자:

        Access denied for user: '@unknown' to database mysql

이것은 user 테이블에 User 컬럼 = root 라는 목록이 없고, mysqld가 사용자 클라이언트의
호스트이름을 해석할 수 없다는 것을 의미한다. 이런 경우 --skip-grant-tables 옵션을 이
용해 서버를 다시 시작해야 하고 '/etc/hosts' 를 편집하거나 '\windows\hosts' 파일에 사
용자 호스트 목록을 추가해야 한다.

- 3.22.11 이전 버전에서 3.22.11이나 이후 버전으로 업데이트했다면, mysql_fix_privilege
_tables 스크립트를 실행했는가? 하지 않았다면 실행하자. mysql 3.22.11에서 GRANT 문 기
능이 가능해지면서 승인 테이블 구조가 바뀌었다.

- (INSERT 나 UPDATE 문을 사용해) 승인 테이블을 직접 고쳤고 변화가 아직 반영되지 않은
것으로 보이면, FLUSH PRIVILEGES 문을 사용하거나 mysqladmin flush-privileges 명령을 사
용해 서버가 승인 테이블을 다시 읽도록 해야 한다는 것을 기억하자.그렇지 않으면 서버가
재시작하기 전까지는 변화된 것이 반영되지 않는다. root 비밀번호를 설정하고 나서 권한을
flush 하기까지는 비밀번호를 명시할 필요가 없다. 왜냐면 서버는 아직 비밀번호를 바꾸었
는지 모르기 때문이다.

- 세션 중간에 권한이 변경된 것으로 보이면 슈퍼유저가 바꾸었을 것이다. 승인 테이블을
재시작하는 것은 새로운 클라이언트 접속에 영향을 미치지만 이미 존재하고 있던 연결은 6.
7 [Privileges changes]에서 설명한대로 영향을 미친다.

- 시험하기 위해, mysqld 대몬에  --skip-grant-tables 옵션을 주어 시작하자. 그러고나서
mysql 승인 테이블을 변경할 수 있고 변경된것이 원하는대로 작동하는지를 체크하는 mysqla
ccess 스크립트를 사용할 수 있다. 원하는대로 수정이 되었으면 mysqld 서버가 새로운 승인
테이블로 시작할 있도록 mysq1admin flush-priveleges 를 실행한다.
주의 : 승인테이블을 재로딩하는 것은 --skip-grant-tables 옵션을 무효화한다. 이를 통해
서버를 다운시키고 다시 재시작하지 않고도 승인 테이블을 시작할 수 있다.

- 펄, Python, ODBC 프로그램에서 접근하는데 문제가 있다면, mysql -u user_name db_name 
또는 mysql -u user_name -pyour_pass db_name 으로 서버에 접속을 시도해보자. (-p 와 비
밀번호사이에는 공백이 없다는 것을 기억하자. 또한 --password=your_pass 형태로도 사용할
수 있다) mysql 클라이언트로 접속이 되면 프로그램에 문제가 있는 것이며 접근 권한에는
문제가 없다.

- 비밀번호가 제대로 작동하지 않으면, INSERT, UPDATE, SET PASSWORD 문에서 비밀번호를
설정하면서 PASSWORD() 함수를 반드시 사용해야 한다는 것을 기억하자. PASSWORD() 함수는
GRANT ... INDENTIFIED BY 문이나 mysqladmin password 명령을 사용했다면 불필요하다. 6.1
0 [Passwords] 참고.

- localhost 는 지역 호스트 이름과 같은 말이다. 또한 호스트를 명백하게 설정하지 않은
경우 클라이언트에서 연결하려는 호스트의 기본값이다. 그러나 MIT-pthreads를 사용하는 시
스템에서는 localhost로의 연결이 제대로 작동하지 않는다. (localhost 연결은 유닉스 소켓
을 통해 만들어진다. 그렇지만 MIT-pthreads에서는 유닉스 소켓을 지원하지 않는다.) 이와
같은 시스템에서 문제를 피하려면, 서버에 호스트 이름을 명확하게 말해주기 위해 --host
옵션을 사용해야 한다. 그러면 mysqld 서버에 TCP/IP 연결을 만든다. 이경우, 서버 호스트
의 user 테이블 목록에 실제 호스트이름이 있어야 한다. (서버와 동일한 호스트에서 클라이
언트 프로그램을 실행한다고 하더라도 마찬가지이다.)

- mysql -u user_name db_name 으로 데이터베이스에 접속하려 할 때 접근 거부 에러가 나
면, user 테이블에 문제가 있을 것이다. mysql -u root mysql 를 실행하여 점검하고 다음의
SQL 문을 사용하자:

        mysql> SELECT * FROM user;

여기서 사용자의 호스트이름과 mysql 사용자 이름과 맞는 Host 와 User 컬럼의 목록이 포함
되어 있어야 한다.

- Access denied 에러 메시지는 접속하려는 사용자와 호스트 이름, 그리고 비밀번호를 사용
했는지 여부를 보여줄 것이다. 일반적으로 user 테이블에 에러 메시지에서 보여준 호스트
이름과 사용자 이름과 정확하게 맞는 목록을 가지고 있어야 한다.


- 다른 시스템에서 mysql 서버에 접속할 때 다음의 에러 메시지가 나오면, user 테이블에
연결을 하려고 하는 호스트 이름이 없다는 것을 말한다:

        Host ... is not allowed to connect to this MySQL server

(서버 호스트에서!) 명령행 유틸리티인 mysql을 사용하여 user 테이블에 연결하고자 하는
사용자/호스트 이름을 추가하여 해결할 수 있다. mysql 3.22 를 사용하고 있지 않고 연결하
고자 하는 시스템의 IP 숫자나 호스트 이름을 모른다면, user 테이블에 Host 컬럼 값으로
'%' 목록을 입력하고 서버 시스템에서 --log 옵션을 사용해 mysqld 를 재시작하자. 클라이
언트 시스템에서 연결을 시도한 후 mysql 로그에는 어떻게 실제로 연결을 했는지에 대한 정
보가 들어있다. (그러고나서 '%'를 로그에 나온 실제 호스트 이름으로 바꾼다. 그렇지 앟으
면 보안에 문제가 생길 수 있다.)

- mysql -u root test 는 작동을 하는데 mysql -h your_hostname -u root test 에서 접근에
에러가 나면, user 테이블에 정확한 호스트 이름이 없을 것이다. 일반적인 문제는 user 테
이블의 Host 값에는 완전하지 않은 호스트 이름(** 도메인은 빼고 호스트 이름만 넣은 경우
**) 이 들어가 있는데 시스템의 네임 해석 루틴은 FQDN(fully-qualified domain name - **
완전한 도메인 이름과 호스트 이름을 사용**)으로 처리하는 경우이다(또는 거꾸로 해석).예
를 들어, user 테이블에 호스트 이름이 'taejun' 으로 되어있는데, DNS는 mysql에 호스트
이름이 'taejun.subnet.se'라고 알려줄 수 있으며 이경우는 제대로 작동하지 않을 것이다.
user 테이블에 Host 컬럼 값으로서 해당하는 IP 숫자나 호스트 이름을 추가하자. (대신, us
er 테이블에 Host 값으로 와일드카드 문자를 포함할 수 있다. 예를 들어, 'taejun.%'. 그러
나 호스트이름 끝에 '%'를 사용하는 것은 안전하지 않으며 권하지도 않는다!)

- mysql -u user_name test 는 작동하는데 mysql -u user_name other_db_name 은 작동하지
않는다면 db 테이블에 other_db_name 목록이 없는 경우이다.

- 서버 시스템에서 mysql -u user_name db_name 은 작동을 하는데, 다른 클라이언트 시스템
에서 mysql -u user_name db_name 은 작동을 하지 않는다면, user 테이블이나 db 테이블에
클라이언트 시스템의 목록이 없는 것이다.

- 왜 Access denied 가 나는지 해결하지 못하면, user 테이블에서 와일드카드('%' 또는 '
_')를 포함하고 있는 Host 값을 가진 목록을 모두 제거하자. 매우 일반적인 에러는 Host='%
' 그리고 User='some user'로 입력을 하고나서 , 이렇게 하면 같은 시스템에서 연결할 때 l
ocalhost를 지정할 수 있도록 허용한다고 생각하는 것이다. 이것이 제대로 작동하지 않는
이유는 기본 권한에 Host='localhost' 와 User='' 목록이 포함되어 있기 때문이다. Host 값
에 '%' 보다 더 분명한 'localhost' 목록이 있기 때문에, localhost에서 접속할 때 새로운
목록보다 먼저 선택이 된다. 정확한 절차는 두번째 항목으로 Host='localhost' 와 User='so
me_user' 를 입력하거나 Host='localhost' 와 User='' 를 제거하는 것이다.

- 다음의 에러가 나는 경우:

        Access to database denied

db 나 host 테이블에 문제가 있을 것이다. 선택한 db 테이블의 목록에 Host 컬럼이 비어있
다면, host 테이블에 db 테이블 목록에 적용되는 호스트 이름이 있는지를 확인해야 한다.
(** 일반적으로 db 테이블에 host 값을 비워두는 경우, host 테이블에서 접근하는 호스트를
제어할 수 있다 **)

- 다음의 에러가 나는 경우:


        Access to database denied

SELECT ... INTO OUTFILE 또는 LOAD DATA INFILE 의 SQL 문을 사용하는 경우, user 테이블
목록에서 file 권한이 설정되어 있지 않았을 것이다.

- 다른 모든 것이 실패하였을 경우, mysqld 대몬을 디버깅 옵션으로 시작하자. (예를 들어,
--debug=d,general,query) 그러면 각 명령에서 생기는 정보와 함께, 접속을 시도하는 호스
트와 사용자에 대한 정보를 출력할 것이다. G.1 [Debugging] 참고.

- mysql 승인 테이블에서 다른 문제에 부딪쳤고 이 문제를 메일링리스트에 알려야겠다고 느
끼면, mysql 승인 테이블을 덤프하여 제공해야 한다. mysqldump mysql 명령을 사용해 테이
블을 덤프할 수 있다. 언제나 mysqlbug 스트립트를 사용하여 문제를 올리자.

- 다음의 에러가 나는 경우, mysqld 대몬이 실행되지 않거나 잘못된 소켓이나 포트로 연결
하려고 시도하는 경우:

        Can't connect to local MySQL server
        Can't connect to MySQL server on some_hostname

먼저 mysqld 대몬이 실제로 작동하는지 ps를 이용해 확인한다. 소켓 파일이 있느지 확인하
고 점검을 해 보아야 한다.(일반적으로 `/tmp/mysql.sock' 임) 또는 telnet host_name 3306
으로 접속을 시도해보자. 더 자세한 정보를 위해 mysqladmin version 과 mysqladmin -h hos
t_name version 을 사용해 볼 수 있다. 물론 참고할 것이 있는지 mysql 데이타 디렉토리의
에러 로그 파일을 점검해보자.

{{}}{{}}{{}}- 클라이언트 프로그램은 설정 파일이나 환경 변수에서 지정한 연결 패러미터를 사용할 수
있다는 것을 기억하자. 명령행에서 지정하지 않았는데 클라이언트가 잘못된 기본 연결 패러
미터를 보내는 것으로 생각되면, 홈 디렉토리에서 환경변수나 '.my.cnf' 파일을 점검해보
자. 비록 여기서 지정한 연결 패러미터와는 관계가 멀지만 시스템의 전반적인 mysql 설정
파일을 점검해 볼 수 있다. 4.14.4 [Option files] 참고. 클라이언트에서 아무런 옵션도 주
지 않았는데 Access denied 에러 메시지가 나오는 경우, 옵션 파일 중에서 예전의 비밀번호
를 지정하지 않았는지 확인해 보자. 4.14.4 [Option files] 참고.

 


6.12 크랙커에 대비하여 mysql을 안전하게 하는 방법

mysql 서버에 연결할 때 일반적으로 비밀번호를 사용해야 한다. 비밀번호는 연결할 때 단순
한 텍스트로 전송되지 않는다.

서버/클라이언트 연결은 암호화되지 않는다; 모든 정보는 연결을 볼 수 있는 누구라도 읽을
수 있는 텍스트로 전송된다. 이 문제에 대해 걱정이 되면 문제를 어렵게 하기 위해 압축 프
로토콜(mysql 3.22 이상 버전)을 사용할 수 있다. 보안을 더 확실하게 하기 위해 ssh를 설
치할 수 있다. (http://www.cs.hut.fi/ssh 참고) 이것을 이용해 mysql 서버와 클라이언트
사이에 암호화된 TCP/IP 연결을 사용할 수 있다.

mysql 시스템의 보안을 유지하게 위해 다음의 제안을 신중하게 고려하자:

- 모든 mysql 사용자가 비밀번호를 사용. 어떤 사용자가 비밀번호가 없으면 'mysql - u 사
용자이름' 을 이용해 간단하게 그 사용자로 로그인할 수 있다는 것을 기억하자. 이것은 클
라이언트/서버 애플리케이션의 일반적인 작동방법이다. mysql_install_db 스크립트를 실행
하기 전에 이 스크립트를 수정하여 모든 사용자의 비밀번호를 바꿀 수 있다. 또는 mysql ro
ot 사용자의 비밀번호를 바꿀 때는 다음과 같이 하면 된다:

shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
           WHERE user='root';
mysql> FLUSH PRIVILEGES;

- mysql 데몬을 유닉스의 root 사용자로 시작하지 말자. mysqld 는 다른 사용자가 실행할
수 있다.또한 보안을 더 엄격하게 하기 위해 mysql이라는 유닉스 사용자를 만들 수 있다.
다른 유닉스 사용자로 mysqld를 실행하면 user 테이블에서 root 사용자 이름을 바꿀 필요가
없다. mysqld를 다른 유닉스 사용자가 시작하기 위해 mysql.server 스크립트를 수정하면 된
다. 일반적으로 su 명령을 사용한다. 더 자세한 내용은 16.7 [Changing mysql user] 참고.

- mysqld를 실행할 수 있는 사용자만이 데이터베이스 디렉토리에 읽기/쓰기 권한을 가지고
있는지 확인.

- 모든 사용자에게 process 권한을 주지 말자. mysqladmin processlist 을 출력하면 현재
실행하는 쿼리의 내용을 볼 수 있다. 그러므로 이러한 명령을 실행할 권한이 있는 사용자는
다른 사용자의 UPDATE user SET password=PASSWORD(_'no_secure') 질의를 볼 수 있다.mysql
은 process 권한을 가진 사용자를 위해 추가적인(extra) 연결을 저장한다.그래서 mysql roo
t 사용자는 모든 일반적인 연결이 사용되었어도 로그인하고 점검을 할 수 있다.

- 모든 사용자에게 file 권한을 주지 말자. 이러한 권한이 있는 사용자는 mysqld 대몬의 권
한이 있는 파일 시스템의 어느 곳에라도 파일을 저장할 수 있다.좀 더 안전하게 하기 위해
SELECT ... INTO OUTFILE 로 생성되는 모든 파일은 모든 사용자가 읽기만 할 수 있으며 이
미 존재하는 파일을 덮어씌울 수 없다.
(** file 권한은 LOAD DATA INFILE , SELECT .. INTO OUTFILE 문을 이용하여 서버에 파일을
저장하고 읽을 수 있는 권한을 허용한다. 이러한 권한을 가진 사용자는 mysql 서버가 읽고
쓸 수 있는 파일을 읽고 쓸 수 있는 권한이 허용된다. 일반 사용자에게 이런 권한을 줄 필
요는 없다. 필요한 부분만 권한을 주는 것이 좋다. 권한을 남용말자. **)

- DNS 를 신뢰하지 못한다면 승인 테입르에서 호스트이름 대신 IP를 사용하자. 기본적으로
mysqld 의 --secure 옵션은 호스트이름을 안전하게 한다. 어떤 경우 와일드카드 문자가 포
함된 호스트이름 값을 사용할때는 매우 조심해야 한다.

- mysql.server 스크립트에서 유닉스 root 사용자의 비밀번호를 넣는다면, 이 스크립트는
오직 root만이 읽을 수 있도록 해야 한다.

다음의 mysqld 옵션은 보안과 관련되어 있다:

--secure : gethostbyname() 시스템 콜에 의해 리턴된 IP 숫자가 원래의 호스트이름을 reso
lve 한 것과 같은지를 점검한다. 이것은 어떤 사람이 다른 호스트 이름을 에뮬레이터해서
접근하는 것을 어렵게 만든다. 이 옵션은 또한 호스트이름이 온전한지에 대한 점검을 추가
한다. 해석하는데 때로는 시간이 많이 걸려서 mysql 3.21에서는 기본적으로 설정이 되어 있
지 않다. mysql 3.22에서는 호스트이름을 캐쉬하고 이 옵션이 기본적으로 설정되어 있다.
(** 함수 gethostbyname()은 호스트 이름을 인자로 받아 그에 해당하는 IP 주소 및 기타 정
보를 해당하는 구조체에 담아 그 구조체의 포인터를 리턴하는 함수입니다. 쉽게 말해서 호
스트 이름을 넣으면 해당 IP 주소를 찾아주지요.**)

--skip-grant-tables : 이 옵션을 사용하면 서버가 권한 시스템을 전혀 사용하지 않는다.
그러면 모든 사용자가 모든 데이터베이스에 접속할 수 있다! (mysqladmin reload 를 실행하
여 실행중인 서버가 승인 테이블을 사용하도록 할 수 있다.)

--skip-name-resolve : 호스트이름이 해석되지 않는다. 승인 테이블의 모든 Host 컬럼값은
반드시 IP 숫자이거나 로컬호스트이어야 한다.

--skip-networking : 네트웍을 통한 TCP/IP 연결을 허용안함. mysqld와 모든 연결은 유닉스
도메인 소켓을 통해 만들어진다. 이 옵션은 MIT-pthreads를 사용하는 시스템에서는 제대로
작동을 하지 않는다. 왜냐면 MIT-pthreads 패키지는 유닉스 소켓을 지원하지 않기 때문이
다. (** 리눅스를 사용하는 사람들에게는 상관없겠죠? 유닉스 도메인 소켓을 지원하니깐.
이와 비슷하게 postgres도 6.3버전 이후부터인가요? 기본적으로 유닉스 도메인 소켓으로 바
뀌었지요. **)


관련글 더보기