CREATE, DROP 구문
CREATE 구문 - 데이터베이스 생성
CREATE DATEABASE [DB_NAME];
CREATE DATABASE test_db;
CREATE 구문 - 테이블 생성
CREATE TABLE [NAME] ([COLUMN_NAME] [DATA_TYPE]);
CREATE TABLE test_tb (name char(20), age int);
DROP 구문 - 데이터베이스/테이블 삭제
DROP [DATABASE/TABLE] [NAME];
DROP TABLE test_tb;
실습
XAMPP 컨트롤 패널 열고 MySQL의 Start 버튼 클릭하여 시작 후 우측의 Shell 클릭하여 CMD 창 열기
mysql -u root -p 입력 후 비밀번호 입력 창에서 엔터 눌러서 로그인(비밀번호 없으므로 가능)
show databases; 입력하여 데이터베이스 목록 출력
create database example; 입력하여 example 이라는 데이터베이스 생성
show databases; 입력하여 생성된 데이터베이스 확인
select database(); 입력하여 현재 선택된 데이터베이스 확인, NULL은 현재 선택된 값이 없기 때문에 출력됨.
DB 선택을 위해서 use 명령어를 사용하여 DB를 선택한다.
use example; 입력하여 example 데이터베이스 선택한다.
select database(); 입력하여 현재 선택된 데이터베이스가 example 데이터베이스 인것을 확인
create table member(seq int, name char(20), email char(50));
→ 컬럼명 seq는 숫자, name은 문자열 20, email은 문자열 50 인 member 테이블 생성
show tables; 입력하여 member 테이블 생성 확인
describe 명령어 사용하여 테이블 구조를 확인할 수 있다.
describe member; 또는 desc member;를 입력하여 테이블 구조를 확인한다.
INSERT, SELECT, UPDATE, DELETE 구문
INSERT 구문 - 데이터 삽입
INSERT INTO [TABLE_NAME] ([COLUMN1]...) VALUES ([DATA1]...);
INSERT INTO test_tb (name, age) VALUES ('honggildong', 55);
→ 컬럼명이 생략된 경우, 기존 컬럼명 순서대로 데이터 삽입을 의미
→ 특정 컬럼에 삽입을 원하는 경우 컬럼명 명시해야 함
SELECT 구문 - 데이터 조회
SELECT [COLUMN1] FROM [TABLE] WHERE [CONDITION];
SELECT name, age FROM test_tb;
SELECT * FROM test_tb;
SELECT name,age FROM test_tb WHERE id='admin';
→ test_tb 테이블에서 id가 admin인 사용자에 대한 name과 age값을 출력
UPDATE 구문 - 데이터 수정
UPDATE [TABLE] SET [COLUMN1]=[DATA1] WHERE [CONDITION];
UPDATE test_tb SET age=35 WHERE name='honggildong';
→ WHERE 절이 없으면 테이블의 모든 age 값이 35로 변경된다.
DELETE 구문 - 데이터 삭제
DELETE FROM [TABLE] WHERE [CONDITION];
DELETE FROM test_tb WHERE name='honggildong';
→ WHERE 절이 없으면 테이블의 모든 값이 삭제된다.
실습
insert into member(seq, name, email) values(1, 'administrator', 'administrator@test.com');
insert into member(seq, name, email) values(2, 'user', 'user@test.com');
insert into member(seq, name, email) values(3, 'guest', 'guest@test.com');
insert into member(seq, name, email) values(4, 'hong', 'hong@test.com');
insert into member(seq, name, email) values(5, 'lee', 'lee@test.com');
입력하여 각 컬럼에 데이터 삽입
select * from member; 입력하여 삽입된 데이터 확인
select name, email from member;
→ seq를 제외한 name과 email 컬럼의 데이터를 출력한다.
select name, email from member where seq=1;
→ seq가 1인 name과 email 컬럼의 데이터를 출력한다.
insert into member values(6, 'test', 'test@test.com');
→ seq는 6, name은 test, email은 test@test.com 데이터를 삽입
→ 컬럼명이 생략된 경우, 컬럼명 순서대로 데이터 삽입을 의미한다.
select * from member; 입력하여 삽입된 데이터 확인
update member set name='test1' where seq=6;
→ seq가 6인 name을 test1로 변경한다.
update member set name='test1' where name='test';
→ name이 test인 name을 test1로 변경한다.
위 2개중 어느것을 사용해도 상관없다. test를 test1로 변경한다.
delete from member where seq=6;
→ seq가 6인 레코드를 삭제
select * from member; 입력하여 데이터 삭제 확인
연산자
연산자와 피연산자의 관계
산술 연산자
SQL 구문으로 산술 연산이 가능하다.
select 1+4; 입력 시 답은 5가 나온다.
select 1+4*2; 입력 시 답은 9가 나온다.
산술 연산으로 데이터 출력하기
select * from member where seq=6-1;
→ select * from member where seq=5; 와 동일하다.
→ Injection이 발생된다는 하나의 추론이 된다.
비교 연산자
select * from member where seq>=2;
→ seq 가 2보다 크거나 같은 데이터를 출력
select * from member where seq !=4;
→ seq 가 4가 아닌 데이터를 출력
논리 연산자
NOT → True는 False로, False는 True로
AND → 둘다 True 여야 True 성립됨, 하나라도 False면 False
OR → 둘중 하나라도 True면 True 성립됨. 둘다 False 면 False
select * from member where seq=1 or seq=5;
→ seq가 1 또는 5인 데이터를 출력
select * from member where seq=5 and name='lee';
→ seq가 5 이고 name이 lee인 데이터를 출력
비트 논리 연산자
XOR = 배타적 논리합 = 둘중 하나만 True인 경우에만 True가 됨. True True 또는 False False 인 경우 False가 됨.
AND → 둘다 1이여야 1 성립됨, 하나라도 0이면 0
OR → 둘중 하나라도 1이면 1 성립됨. 둘다 0 이면 0
10진수를 2진수로 변환 후 비트 연산을 한다.
select 1&1;
→ 둘다 1이므로 True = 1
select 2&1;
→ 10과 01을 AND 연산 = 00
select 3&1;
→ 11과 01을 AND 연산 = 01
select 5&3;
→ 101과 011을 AND 연산 = 001
select 5|2;
→ 101 과 010을 OR 연산 = 111 = 7
비트 논리 연산자를 알아야 하는 이유
→ SQL Injection의 Blind Based SQL Injection에서 가장 많이 사용하는 방법이다.
연결 연산자
피연산자 1과 2가 문자열이 사용될 때 MySQL에서 공백으로 연산자를 사용한다.
select 'te' 'st'
→ test 문자열 출력
select * from member where name='gue' 'st';
→ member 테이블에서 name이 guest인 데이터 출력
select concat('adm','inis','trator');
→ adm inis trator 문자열 합쳐서 출력
IN 연산자
SELECT name, email FROM member WHERE id in('admin','guest');
= SELECT name, email FROM member WHERE id='admin' or id='guest';
→ OR 연산자를 여러 개를 사용하는 것 보다, IN 연산자를 사용하면 가독성이 좋으며 실행속도도 더 빠르다.
SELECT name, email FROM member WHERE id not in('admin','guest');
→ id에 admin과 guest를 제외한 레코드를 출력
select * from member where name in ('administrator', 'guest');
→ member 테이블에서 name이 administrator 또는 guest인 데이터를 출력
select * from member where name='administrator' or name='guest';
→ member 테이블에서 name이 administrator 또는 guest인 데이터를 출력
select * from member where name not in ('administrator', 'guest');
→ member 테이블에서 name이 administrator 또는 guest가 아닌 데이터를 출력
LIKE 연산자
LIKE 연산자 = 부분적으로 알고 있는 문자열 패턴에 대해 검색할 수 있는 연산자
웹 서비스 검색 기능에 많이 사용되며, 일부 문자만 알아도 검색이 가능하다.
% → 와일드카드
select * from member where name like '%admin%';
→ member 테이블의 name 컬럼에 admin 문자열이 포함된 데이터 출력
select * from member where name like 'gu_st';
→ member 테이블의 name 컬럼에 gu_st 만 알고 특정 문자열을 모를 때 데이터 출력
select * from member where email like '%@test.com';
→ member 테이블의 email 컬럼에 test.com으로 끝나는 이메일 주소를 가진 데이터 출력
함수
문자열 함수
SUBSTRING - 문자열을 자를 때 사용하는 함수
SUBSTRB - Byte 단위로 자르는 함수
SUBSTRING은 SQL Injection 공격 시 많이 사용되는 함수이다.
Blind based Injection 에서 문자열 하나하나 추출하여 ASCII 코드로 변환 후 비트 연산 후 해당 문자를 추론하는 등 자주 사용된다. 또한 MySQL은 3개의 함수를 사용할 수 있으며, 1개의 함수를 block 해도 나머지 2개 함수로 우회가 가능하다.
select substring('test', 1, 1);
→ test 문자열의 첫번째 문자에서 1개 글자 출력
select substring('test', 2, 1);
→ test 문자열의 두번째 문자에서 1개 글자 출력
select substring('test', 3, 1);
→ test 문자열의 세번째 문자에서 1개 글자 출력
select substring('test', 2, 3);
→ test 문자열의 두번째 문자에서 3개 글자 출력
select substr('test', 1, 3);
→ test 문자열의 첫번째 문자에서 3개 글자 출력
select mid('test', 1, 3);
→ test 문자열의 첫번째 문자에서 3개 글자 출력
문자, 아스키 코드 변환 함수
ASCII 코드 → 문자 인코딩 기술
컴퓨터는 0,1 이진수만 식별 가능한데, 문자열을 컴퓨터가 인식할 수 있도록 해주는 코드가 ASCII 코드이다.
select ascii('a');
→ a 문자열을 ASCII 코드로 변환
select bin(ascii('a'));
→ a 문자열을 ASCII 코드로 변환 후 이진수로 변환
select ascii(substr('test', 1, 1));
→ test 문자열의 첫번째 문자에서 1개 글자 출력 후 ASCII 코드로 변환
select ascii(substr('test' , 2, 1));
→ test 문자열의 두번째 문자에서 1개 글자 출력 후 ASCII 코드로 변환
select ascii(substr('test', 3, 1));
→ test 문자열의 세번째 문자에서 1개 글자 출력 후 ASCII 코드로 변환
select bin(ascii(substr('test', 3, 1)));
→ test 문자열의 세번째 문자에서 1개 글자 출력 후 ASCII 코드로 변환 후 이진수로 변환
CHAR 함수 → ASCII 코드에서 문자열로 변환
select char(97);
→ ASCII 코드 97을 문자열로 변환
select concat(char(97), char(97));
→ 2개의 ASCII 코드 97을 문자열로 변환 후 concat 함수로 합쳐서 출력
싱글 쿼터 ' 를 사용하지 못하는 환경에서 concat 함수를 사용하는데, 특정 문자열을 사용하고 싶을 때 concat 함수를 사용할 수 있다.
admin 문자열을 ASCII 코드로 변환 후 concat 함수 사용하여 문자열을 합친다.
select ascii('a'); → 97
select ascii('d'); → 100
select ascii('m'); → 109
select ascii('i'); → 105
select ascii('n'); → 110
select concat(char(97), char(100), char(109), char(105), char(110));
→ char 함수로 ASCII 코드 97, 100, 109, 105, 110을 문자열로 변환 후 concat 함수 사용하여 합친다.
→ admin
COUNT 함수
SELECT COUNT(COLUMN) FROM [TABLE]
→ TABLE에 대한 레코드 개수를 구하는 함수
select * from member;
→ member 테이블에서 전체 컬럼에 대한 레코드 출력
select count(*) from member;
→ member 테이블에서 전체 컬럼에 대한 레코드 개수 출력
COUNT 함수를 사용하여 레코드 개수를 알 수 있다.
데이터 개수를 알아야지 임계값(목표값)을 알 수 있다.
자동화 도구 사용 시 임계값 지정해서 실행하기 때문에 COUNT 함수는 SQL Injection 공격에서 유용하다.
길이 함수
COUNT 함수와 동일하게 SQL Injection 공격 시 유용하게 사용된다.
문자열에 대한 임계값을 확인하기 위해 길이 함수가 사용된다.
레코드에 대한 임계값 확인 → COUNT 함수
데이터 길이에 대한 임계값 확인 → LENGTH 함수
select length('test');
→ test 문자열의 길이 출력
select name, length(email) from member;
→ member 테이블에서 name컬럼 출력, email 컬럼의 데이터 길이를 출력
조건문
조건문 → 조건의 결과에 따라 값을 반환하는 구문
DBMS 별로 공통된 CASE WHEN 구문이 있다.
CASE WHEN 구문 사용법
select case when 1=1 then 1 else 2 end;
→ 1=1 이 참일 경우 1 출력, 거짓일 경우 2 출력
select case when 1=1 then 'True' else 'False' end;
→ 1=1 이 참일 경우 True 출력, 거짓일 경우 False 출력
select case when 1=2 then 'True' else 'False' end;
→ 1=2 가 참일 경우 True 출력, 거짓일 경우 False 출력
member 테이블의 seq 에 대해 CASE WHEN 구문 사용하기
select * from member where seq=(case when 1=1 then 1 else 2 end);
→ 1=1이 참인 경우 member 테이블에서 seq가 1인 레코드 출력
select * from member where seq=(case when 1=2 then 1 else 2 end);
→ 1=2가 거짓인 경우 member 테이블에서 seq가 2인 레코드 출력
CASE WHEN 구문은 실제 공격 시 조건문[CONDITION]에 원하는 데이터를 추론할 수 있는 공격 페이로드가 담긴다.
조건문에는 특정 DB, 특정 컬럼의 데이터를 담고 있는데, 해당 데이터가 참인지 거짓인지 결과값에 따라서 데이터를 추론할 수 있다.
서브쿼리
서브쿼리(SubQuery) 개념
SELECT, FROM, WHERE 절에 따른 서브 쿼리 명칭
스칼라 서브쿼리 = 1개의 레코드와 1개의 컬럼만 반환한다. → 1개의 데이터만 반환가능
인라인 뷰 = 1개 이상의 테이블을 기반으로 만들어진 논리적인(가상) 테이블, 다수 컬럼 다수 레코드 반환 가능
일반 서브쿼리 = 연산자에 따라서 반환되는 레코드와 컬럼의 개수가 다르다.
서브쿼리 종류
= 사용 시 단일 행 반환
in 사용 시 다수 행 반환
스칼라 서브쿼리 사용
select name, (select version()) from member;
→ member 테이블에서 name과 버전 정보를 출력
→ 레코드 생성될 때 마다 버전 정보 같이 출력
SELECT에서 사용하는 스칼라 서브쿼리는 1개의 레코드와 1개의 컬럼만 반환 가능하다.
2개 이상 개수는 오류 발생
select name, (select email from member where seq=a.seq) from member a;
→ member 테이블에서 name과 member 테이블(a)의 email을 출력
여러 테이블을 사용하는 경우가 있는데, 이때 테이블에 별칭(a)을 사용하지 않으면 충돌이 발생할 수 있다.
인라인 뷰
select * from (select * from member)a;
→ a라는 별칭을 가진 member 테이블(가상 테이블) 데이터 출력
select * from (select * from member)a where a.seq=1;
→ a라는 별칭을 가진 member 테이블(가상 테이블)의 seq가 1인 데이터 출력
일반 서브쿼리
select * from member where seq=(select * from member where name='guest');
→ member 테이블에서 seq를 출력하는데, seq는 member 테이블에서 name이 guest인 데이터
다수 행 서브쿼리를 사용할 경우 = 대신 in 을 사용한다.
select * from member where seq in(select seq from member);
→ member 테이블에서 seq를 출력하는데, seq는 member 테이블의 seq인 데이터
ORDER BY 절을 이용한 레코드 정렬
ORDER BY절 사용법
ASC = 컬럼을 기준으로 오름차순, 생략 가능
DESC = 컬럼을 기준으로 내림차순
오름차순은 큰 수를 기준으로, 아래에서 위로
내림차순은 큰 수를 기준으로, 위에서 아래로
정렬은 게시판, 쇼핑몰 등에서 자주 사용된다.
select * from member order by seq asc;
→ member 테이블에서 seq를 오름차순으로 데이터 출력
→ asc는 생략이 가능
select * from member order by seq desc;
→ member 테이블에서 seq를 내림차순으로 데이터 출력
ORDER BY 절 정렬을 위해 데이터 추가
insert into member values(2, 'admin', 'admin@test.com');
→ member 테이블에 seq는 2, name은 admin, email은 admin@test.com인 데이터 삽입
select * from member order by seq;
→ member 테이블에서 seq를 오름차순으로 데이터 출력
seq는 오름차순으로 정렬되었지만, name은 정렬되지 않았다. name도 오름차순으로 정렬해본다.
select * from member order by seq, name;
→ member 테이블에서 seq, name을 오름차순으로 데이터 출력
컬럼이 아닌 숫자를 사용하여 정렬 가능하다.
select * from member order by 1;
→ member 테이블에서 첫번째 컬럼(seq)을 오름차순으로 데이터 출력
select * from member order by 2;
→ member 테이블에서 두번째 컬럼(name)을 오름차순으로 데이터 출력
만약 SELECT 절에 seq, name 컬럼이 있는 경우 ORDER BY에 3이 인식이될까?
select seq, name from member order by 3;
→ member 테이블에서 seq와 name을 출력하는데, 세번째 컬럼을 기준으로 오름차순 정렬을 한다.
→ 첫번째, 두번째 컬럼인 seq와 name의 데이터는 출력되지만, 세번째 컬럼인 email 데이터는 없으므로 에러 발생
→ member 테이블 내 데이터 존재 여부가 아닌, SELECT에 의한 출력 여부가 중요하다.
레코드 출력 개수 제한
레코드 출력 개수 제한 = 특정 목록 개수만 출력 가능하도록 설정
MYSQL의 LIMIT절
OFFSET = 시작 위치, 0부터 시작, 생략 가능
ROW_COUNT = 레코드 개수
select * from member limit 3;
→ member 테이블에서 첫번째부터 3개 레코드 출력
select * from member limit 1,4;
→ member 테이블에서 두번째부터 4개 레코드 출력
순차적 레코드 출력
select * from member limit 0,1;
→ member 테이블에서 첫번째부터 1개 레코드 출력
select * from member limit 1,1;
→ member 테이블에서 두번째부터 1개 레코드 출력
select * from member limit 2,1;
→ member 테이블에서 세번째부터 1개 레코드 출력
select * from member limit 3,1;
→ member 테이블에서 네번째부터 1개 레코드 출력
select * from member limit 4,1;
→ member 테이블에서 다섯번째부터 1개 레코드 출력
select * from member limit 5,1;
→ member 테이블에서 여섯번째부터 1개 레코드 출력
SQL 기본 문법 활용 예제
예제1 ~ 예제12
예제 풀기 전에 이전에 update로 추가한 admin 레코드를 삭제한다.
delete from member where name='admin';
예제 1) member 테이블의 name이 "guest"인 레코드를 출력하라.
예제 2) member 테이블의 name이 "guest"인 레코드의 email을 출력하라.
예제 3) member 테이블의 name이 "guest"가 아닌 레코드의 name, email을 출력하라.
예제 4) member 테이블의 name이 "lee" 또는 "hong"인 레코드를 출력하라.
예제 5) member 테이블의 name이 "lee", "hong"이 아닌 레코드를 출력하라.
예제 6) member 테이블의 seq가 2이상, 5미만인 레코드를 출력하라.
예제 7) member 테이블의 seq가 1 또는 3 또는 5인 레코드를 출력하라.
예제 8) member 테이블의 name이 "adm"으로 시작하는 레코드를 출력하라.
예제 9) member 테이블의 email이 "test.com"을 주소로 사용하는 레코드를 출력하라.
예제 10) member 테이블의 name을 레코드를 출력하라. 단, "name : 사용자명" 형식으로 출력하라.
예제 11) member 테이블의 name 값의 앞 3 문자만 출력 후 뒤에는 "###"가 붙도록 출력하라.
예제 12) member 테이블의 레코드를 seq 컬럼 기준으로 내림차순으로 정렬 후 2개의 레코드를 출력하자.
SQL 기본 문법 활용 예제 - 정답
예제 1) member 테이블의 name이 "guest"인 레코드를 출력하라.
→ select * from member where name='guest';
예제 2) member 테이블의 name이 "guest"인 레코드의 email을 출력하라.
→ select email from member where name='guest';
예제 3) member 테이블의 name이 "guest"가 아닌 레코드의 name, email을 출력하라.
→ select name, email from member where name!='guest';
예제 4) member 테이블의 name이 "lee" 또는 "hong"인 레코드를 출력하라.
→ select * from member where name='lee' or name='hong';
→ select * from member where name in('lee', 'hong');
예제 5) member 테이블의 name이 "lee", "hong"이 아닌 레코드를 출력하라.
→ select * from member where name!='lee' and name!='hong';
→ select * from member where name not in('lee', 'hong');
예제 6) member 테이블의 seq가 2이상, 5미만인 레코드를 출력하라.
→ select * from member where seq>=2 and seq<5;
예제 7) member 테이블의 seq가 1 또는 3 또는 5인 레코드를 출력하라.
→ select * from member where seq=1 or seq=3 or seq=5;
→ select * from member where seq in(1, 3, 5);
예제 8) member 테이블의 name이 "adm"으로 시작하는 레코드를 출력하라.
→ select * from member where name like 'adm%';
예제 9) member 테이블의 email이 "test.com"을 주소로 사용하는 레코드를 출력하라.
→ select * from member where email like '%test.com%';
예제 10) member 테이블의 name을 레코드를 출력하라. 단, "name : 사용자명" 형식으로 출력하라.
→ select concat('name : ', name) from member;
예제 11) member 테이블의 name 값의 앞 3 문자만 출력 후 뒤에는 "###"가 붙도록 출력하라.
→ select concat(substr(name, 1, 3), '###') from member;
예제 12) member 테이블의 레코드를 seq 컬럼 기준으로 내림차순으로 정렬 후 2개의 레코드를 출력하자.
→ select * from member order by seq desc limit 2;
→ limit 절은 제일 뒤에 작성해야 에러가 발생하지 않는다.
MySQL 화면 캡처
참고
'웹 해킹 > SQL 기본' 카테고리의 다른 글
SQL Injection을 위한 데이터베이스 기초 (1) | 2024.11.16 |
---|