
로그인: 사용자가 자기 자신을 인증함으로써 컴퓨터 시스템에 대한 접근 권한을 얻는 과정
로그인은 식별과 인증 두 단계로 나뉜다.
1) 식별
식별: 많은 데이터 중에서 특정한 데이터를 가려내는 것
특정 데이터 하나만을 가려내야 하므로 식별정보는 중복되는 값이 아닌, 유일해야 한다.
ex) 아이디, 전화번호
2) 인증
인증: 그 사람이 맞는지 확인하는 작업
우리가 로그인을 할 때 사용하는 인증정보는 비밀번호이다.
인증정보는 보호해야되는 정보로서, DB에 저장할때에도 신경을 써주어야 한다.
우리가 로그인 페이지에서 로그인을 할때에는 어떤 사이트에서든지 아이디와 비밀번호를 한번에 입력한다. 하지만 백엔드에서 로그인 정보를 처리하는 과정은 여러가지 케이스가 존재한다.
1) 식별 · 인증을 동시에 하는 CASE
이 CASE는 DB질의를 한번에 수행해서 로그인을 구현하는 경우이다.
그 과정은 다음과 같다.
select * from member where id='@@' && pw='@@'
if ( 결과가 존재하면)
로그인 성공
else
로그인 실패
2) 식별 인증을 분리해서 하는 CASE
이 CASE는 식별을 먼저 수행하고, 그 결과값의 비밀번호를 비교하여 인증을 수행한다.
그 과정은 다음과 같다.
select pass from member where id='@@'
if (DB비밀번호 == 입력한 비밀번호)
로그인 성공
else
로그인 실패
여기에 2가지 방법을 더 생각해볼 수 있는데, 그 전에 HASH함수를 먼저 이야기 할 필요가 있다.
해시: 임의의 길이를 갖는 데이터를 고정된 길이의 데이터로 매핑하는 단방향 함수
여기서 '단방향' 이라는 것은, HASH함수를 통해 한번 변환된 값은 역방향으로 다시 복구가 불가능하다는 의미이다.
이 HASH함수를 앞선 두 CASE의 비밀번호 부분에 적용시킴으로써 두가지의 로그인 로직을 더 생각해볼 수 있다. (DB에 저장된 비밀번호는 이미 해시처리 되어 저장된 상태이다.)
3) 식별 · 인증을 동시에 하는 경우 with 해시
select * from member where id='@@' && pw=md5('@@')
if ( 결과가 존재하면)
로그인 성공
else
로그인 실패
4) 식별 인증을 분리해서 하는 경우 with 해시
select pass from member where id=''
if (DB비밀번호 == md5(입력한 비밀번호))
로그인 성공
else
로그인 실패
앞서 정리하였던 웹서버의 동작방식을 다시 언급하자면, 클라이언트에서 요청을 보내면 서버에서 응답해주는 단순한 구조이다.
기본적으로 HTTP프로토콜은 'connectless', 'stateless' 한 특성을 가진다.
Connectionless
클라이언트가 요청을 한 후, 응답을 받으면 그 연결을 끊어 버리는 특징.
HTTP는 클라이언트가 request를 서버에 보내면, 서버는 요청에 맞는 response를 클라이언트에 보내고 접속을 끊는다.
Stateless
통신이 끝나면 상태를 유지하지 않는 특징.
연결을 끊는 순간 클라이언트와 서버의 통신이 끝나며 그 상태 정보는 유지하지 않는다.
이러한 특성때문에 서버는 매번 요청을 보낸 클라이언트가 누구인지 확인을 해야만 한다. 따라서 이러한 HTTP 프로토콜의 단점을 보완하기 위해 '쿠키'와 '세션' 이 사용되었다.
1. 쿠키
쿠키: 서버가 어떤 데이터를 브라우저 측에 저장한 후, 다시 그 데이터를 받아오는 기술 또는 그 데이터 자체를 의미한다.
- 쿠키는 HTTP메시지의 header 영역을 통해서 송수신되도록 약속이 되어있다.
// set.cookie.php
<?php
setcookie("username", "test_cookie", time()+60*5);
echo "쿠키 설정 완료";
?>
위 코드는 페이지에 방문시 username이라는 이름에 test_cookie 값을 넣어 쿠키를 5분동안 저장해준다.
이 페이지를 통해 쿠키의 동작과정을 테스트해보자.
1) 서버는 Set-Cookie라는 응답헤더에 브라우저가 수신해야할 쿠키 정보를 명시한다.
<HTTP응답>
Set-Cookie: <이름>=<값>
Set-Cookie: a=1
그렇다면 set_cookie.php를 요청하고, 그 응답 결과에서 Set-Cookie를 확인하여 보자.
| URL을 통해 위에서 작성한 set_cookie.php를 요청 | 응답 패킷의 헤더부분에 username=test_cookie로 쿠키를 저장하는 과정 확인 |
|---|---|
![]() | ![]() |
2) 클라이언트는 저장받은 쿠키를 Cookie라는 요청헤더에 포함하여 파일을 요청한다.
<HTTP요청>
Cookie: <이름>=<값>; a=1
그렇다면 클라이언트가 파일을 요청할때, 저장받은 쿠키를 포함하여 전송하는 과정을 살펴보자.
쿠키를 확인하는 페이지의 코드는 다음과 같다.
// test_cookie.php
<?php
if(isset($_COOKIE["username"]))
echo "Logged in ".$_COOKIE["username"];
else
echo "쿠키가 존재하지 않습니다.";
?>
| 쿠키를 저장받은 이후, test_cookie.php 요청 | 요청 패킷을 보면 저장된 쿠키를 헤더에 포함해서 같이 보내고 있다. | 페이지에서도 쿠키의 값이 정상 출력된다. |
|---|---|---|
![]() | ![]() | ![]() |
이렇듯 서버가 쿠키를 한번 브라우저에 저장하면, 브라우저는 해당 쿠키를 매 요청마다 계속해서 서버로 보내게 된다.
서버 입장에서는 이 쿠키값을 보고 각 요청이 어느 브라우저에서 오는지 판단할 수 있게 되는 것이다.
그러나 쿠키에는 최약점이 존재한다.
쿠키는 '클라이언트' 측에서 시작되는 데이터이므로, 변조가 가능하다.
서버가 저장한 적이 없는 쿠키를 만들거나, 쿠키의 값을 바꿔서 서버에 보낼 수 있는 것이다.
| 프록시 툴을 이용하여 test_cookie.php 페이지를 요청할때 같이 보내는 쿠키의 값을, 변조하여 요청을 전송 | 변조된 쿠키의 값으로 로그인이 된 모습 |
|---|---|
![]() | ![]() |
따라서 이러한 취약점 때문에 유저의 정보를 클라이언트가 아닌, 서버측에 저장하고자 하였다.
이것이 바로 세션이다.
2. 세션
세션: 사용자의 데이터를 서버측에 저장하는 방법
기존 쿠기방식의 최대 단점은 브라우저에 저장되기 때문에 유실/변조/도난의 가능성이 있다는 것이다. 따라서 이 정보를 서버 측에 저장함으로써 단점을 보완하고자 하였다.
그렇다면 세션은 어떻게 동작할까?
| 1) 서버측에는 세션 테이블이 존재한다 | 2) 사용자가 로그인을 하면, 세션 정보를 생성해 세션 테이블에 저장한다 |
|---|---|
![]() | ![]() |
| ○ 세션테이블의 정보는 세션ID와, 데이터 값의 형태를 가진다. | |
| ● 세션ID는 수많은 세션 중 특정 세션을 식별하기 위한 값이다. |
| 3) 서버는 세션 ID를 클라이언트 측에 쿠키로 저장한다. | 4) 클라이언트는 이후 세션ID를 쿠키를 통해 전달함으로써 인증을 한다 |
|---|---|
![]() | ![]() |
| ○ 서버 입장에서는 세션ID를 보고 해당되는 세션을 찾아 인증을 수행한다. |
그렇다면, 코드와 파일을 통해 직접 세션의 동작 과정을 살펴보자.
1) 세션 등록
세션을 생성하는 페이지의 코드는 다음과 같다.
// set_session.php
<?php
session_start();
$_SESSION["username"] = "test_sess";
echo "세션 등록 완료";
?>
이제 set_session.php를 요청하여 세션ID가 쿠키로 저장되었는지 확인하자.
| URL을 통해 set_session.php 요청 | 세션이 생성되어 쿠키로 세션ID가 저장된다 |
|---|---|
![]() | ![]() |
| 응답 패킷의 Set-Cookie 헤더를 통해 세션ID가 클라이언트 측에 쿠키로 저장된다. |
| 쿠키로 저장된 세션ID 확인 | 서버 측에 생성된 세션ID 파일의 내용의 세션 데이터값 확인 |
|---|---|
![]() | ![]() |
| ○ 개발자도구를 통해 set_session 페이지의 쿠키로서 세션ID가 등록된 것을 확인할 수 있다. | ● 서버측에 생성된 세션ID 파일을 열어보면, username 세션과 그 값인 test_sess 가 등록되어있는 것을 확인할 수 있다. |
2) 세션ID를 통해 인증
이제 앞서 쿠키로 받은 세션ID를 요청헤더에 포함시켜 페이지를 요청함으로써 사용자 인증을 받을 수 있게 된다.
세션을 확인하는 코드는 다음과 같다.
// test.session.php
<?php
session_start();
if(isset($_SESSION["username"]))
echo "Logged in ".$_SESSION["username"];
else
echo "세션이 등록되지 않음";
?>
| 세션을 생성받은 이후, test_session.php 요청 | 요청 패킷을 살펴보면, 저장된 세션ID를 헤더에 포함시켜 요청하고 있다. | 확인 페이지에서도 세션값이 정상 출력된다. |
|---|---|---|
![]() | ![]() | ![]() |
여기서 의문점이 하나 들 수도 있다.
쿠키는 변조할 수 있는 취약점이 존재하는데, 그렇다면 세션ID를 쿠키로 저장한다면 똑같이 변조할 수 있는 것이 아닌가?
이는 사실이다. 따라서 누군가 이 세션ID의 값을 유추하지 못하도록 세션ID는 1, 2 와 같은 단순한 값이 아닌 숫자와 알파벳의 랜덤한 조합값을 사용하게 된다!