오래 못 할 짓 하지 않기
[ 보안 기초 ] 2. SQL Injection 본문
SQL Injection이란 [ 코드 삽입 공격 ] 이라고 한다.
SQL = DB에 있는 데이터를 처리하기 위한 언어이다.
● 하나의 서버에서 로그인 작업을 한다고 생각해보자.
1. 사용자가 [ ID / Password ] 를 입력
2. backend에서 SQL로 명령어를 날린다.
[ 데이터 베이스에서 뒤 조건이 맞으면 관련된 정보를 다 줘
▶ ID = ' 사용자가 입력한 ID ' AND Password = ' 사용자가 입력한 Password ' ]
3. 정보가 있을 시에는 그 계정과 관련된 데이터를 넘겨준다.
사용자 입력ID 에 hello 를 넣고 , 사용자 입력Password 에 123을 넣으면
id가 hello 이고, password가 123인 유저의 정보를 준다는 것임
공격자는 이 구조의 허점을 이용한다.
바로 ID값에 따옴표를 추가하는 것이다.
[ 데이터 베이스에서 뒤 조건이 맞으면 관련된 정보를 다 줘
▶ ID = ' ' ' And Password = '' ]
이러면 개발자의 의도를 무시할 수 있다.
여기서 한 단계 더 나아가서 Min_h이라는 사람의 계정으로 들어가려고 한다고 해보자.
당연히 아이디는 알지만 비밀번호는 알지 못한다.
[ 데이터 베이스에서 뒤 조건이 맞으면 관련된 정보를 다 줘
▶ ID = ' Min_h' 뒤에 다 주석' And Password = ' ' ]
다음과 같은 코드를 만들었다면 user_name에 [ bob',20)-- ] 이렇게 넣어준다.
그런 다음 비밀번호는 아무렇게나 쳐도 된다 ( --로 주석처리 되었기 때문에 )
해결법
1. 입력 문자를 16진수로 바꾸고 저장
다음과 같이 input으로 이름과 age를 받고
그 정보들을 hexlify 메소드를 통해 16진수로 바꾼다.
이 정보들이 아래와 같이 DB에 저장된다고 생각하면 된다.
(물론 꺼내올 땐 역hexlify 함)
SQL과 DB에는 문제가 생기지 않을 형태로 넣어주고
꺼낼 때는 다시 사용자가 원하는 형태로 바꿔준다.
이렇게 되면 문제가 되는 형태들도 16진수 형태로 들어가서
주석이 아닌 16진수가 DB와 SQL에 들어가게 된다.
이는 쿼리문 - 입력 데이터를 완벽히 구분할 수 있다면 해결되는 문제이다.
이를 구분하는 걸 " 준비된 선언 " 이라고 하는데 공식 문서에서는 이를 활용하라고 권고한다.
값이 들어가야 하는 부분에 ? 를 넣어준다.
준비된 선언을 사용한다면 우리가 방금 했던 (un)Hexlify도 할 필요가 없다.
코드 ▼
import sqlite3
c = sqlite3.connect('test.db')
cursor = c.cursor()
name = input('name? ')
age = input('age? ')
data = name,age
cursor.execute('CREATE TABLE test(name text,age integer)')
cursor.execute(f"INSERT INTO test VALUES(?,?)",data)
cursor.execute('SELECT * FROM test')
out = cursor.fetchall()
print(out)
c.commit()
Injection 공격을 막기 위한 구조적 방어
● 하버드 아키텍쳐
▶ CPU에 2개의 경로를 통해
[ 명령어를 처리하는 메모리 ] [ 데이터를 처리하는 메모리 ]
이런 구조는 물리적으로 Injection이 불가능하다.
'웹 보안 > 웹 개발자가 알아야하는 보안 기초' 카테고리의 다른 글
[ 보안 기초 ] 4. XSS = Cross Side Scripting (0) | 2024.03.07 |
---|---|
[ 보안 기초 ] 3. Sever side template injection (0) | 2024.03.05 |
[ 보안 기초 ] 1. 보안이란? (0) | 2024.03.04 |