IP 기반 로그인 보안 프로세스 구성과 개발

로그인 보안 프로세스 개발

기업 관리자 입장에서의 고객 계정 해킹에 대해 IP 기반 로그인 보안 프로세스 구성과 개발 애기해 보고자 한다. 최근 스팀을 비롯 N사, S사 등의 대기업들이 해킹을 당하면서 여러 고객들의 개인 정보가 해커들에 노출된 상태이다. 그리고 인터넷이라는 특성상 다른 여러 사이트에서도 동일한 고객 정보가 많이 사용되고 있는 실정인데, 고객의 계정을 해커들이 공격하는 경우는 시스템 보안으로는 막을 수 없다. 하지만 고객 정보를 보호하는 것도 기업 관리자 책임이라 할 수 있다. 그런데 해커들은 취약한 사이트를 통해 이미 정확도 높은 개인 정보를 가지고 있기 때문에 고객의 계정을 해킹으로부터 보호한다는 것은 쉽지 않다. 또한 언제 보안사고가 터질지 모르는 상황에서 고객들에게 계속 패스워드를 변경하라고 강요만 할 수 없을 노릇이다. 그래서 이번 장에서는 계정 로그인 기반 시스템을 분석해 계정을 보호할 수 있는 방법을 찾고, 고객의 계정을 보호할 수 방법을 개발하면서, 우리가 생각해야 하는 보안의 범위에 대해서도 함께 고민해 보자

그럼 로그인에서 해커들은 어떻게 공격할 수 있을지 알아보자.

우리가 계정과 패스워드를 입력하고 로그인 버튼을 누르면, 로그인 서버(인증 서버라고도 한다)는 입력한 계정과 패스워드가 맞는지 확인한 후에 결과가 맞으면 로그인 성공 메시지와 인증 토큰을 부여하고, 틀리면 로그인 실패 메시지를 사용자에게 전달하게 된다. 이와 같은 인증을 아이디 기반 인증방식이라 하는데, 해커들을 이와 같은 인증방식의 약점인 여러 번의 로그인 시도를 진행하여 해당 계정의 패스워드 찾는 방식으로 진행하게 된다. 그런데 일반적으로 사이트 이용자들이 여러 사이트의 계정과 패스워드를 관리하는데, 많은 사이트에 가입된 계정을 일일이 관리하기는 어려우므로, 대부분의 이용자들은 몇 가지 단계별로 계정과 패스워드를 구분하여 관리한다. 중요한 사이트, 중요하지 않은 사이트, 일반 사이트 이 정도로 구분하는데, 대부분은 2개의 분류로 관리한다고 할 수 있다.

이러한 계정 관리는 체인과 같아서 하나의 사이트만이라도 관리가 허술하거나, 해킹을 당한 경우 같은 계정과 패스워드를 사용하는 사이트에서도 동일하게 해킹을 당하게 된다.

IP 기반 로그인 보안 프로세스 구성과 개발

[그림 1] 대부분의 이용자들은 계정을 구분해 동일하게 이용한다

그럼 여기서는 이 연결고리를 끊고, 무차별 로그인 시도를 방지할 수 있는 방법에 대해 알아보자.

1 현재 로그인 보안 프로세스

여러 사이트에서 기본적으로 채용하고 있는 정책으로 특정 횟수 이상 패스워드를 틀리면, 본인인증 또는 그림 문자를 추가하는 등 로그인 입력 과정을 복잡하게 하여 보호하는 방법이다.

[그림 2] D 포털 사이트의 그림 문자 입력 요구 화면, 실명 인증을 같이 요구하는 곳도 많다

하지만 이용자들은 대부분 계정별 동일한 패스워드를 사용한다. 즉 한곳이 해킹되었을 경우 해당 계정명을 가지고 있는 다른 사이트의 경우 거의 90% 이상 패스워드가 동일하기 때문에, 여러 번 패스워드를 실패할 일이 없어진다. 패스워드 실패 통제는 무작위 패스워드 공격에는 효과적이나, 해킹에서 얻은 데이터베이스를 이용한 공격에는 무용지물일 가능성이 높다.

이용자가 사이트별 패스워드를 다르게 하였다 하더라도, 해커 역시 하나의 계정에 여러 사이트에서 수집한 데이터베이스의 패스워드를 대입하기 때문에, 계정 탈취 성공 확률을 낮추기란 쉽지 않다.

[그림3] 아직 여러 사이트들이 계정 위주의 보안 통제를 진행하고 있다

일부 사이트에서는 휴면 계정 잠금 등을 진행해 로그인 성공시 본인 인증을 추가로 진행하여, 보호하고 있지만, 이미 로그인 성공을 하였다는 정보를 해커에게 남기고, 만약 핸드폰, 공인인증서와 같은 소유 인증을 제외한 주민등록번호로만 본인인증을 진행한다면, 웃을 수밖에 없다. 이미 해킹한 데이터베이스에 고객정보는 함께 보관되어 있으니 말이다.

이외에도 여러 업체에서 몇몇 로그인 보안 통제가 적용되어 있지만, 많은 계정 정보가 노출된 지금, 더욱 강도 높은 로그인 보안 체계가 필요한 실정이다.

2 우리가 알아야 할 것

무엇인가를 보호하기 위해서는 보호해야 하는 것이 무엇인지, 어떻게 구성되어 있는지 잘 파악하여야 효과적으로 보호할 수 있다.

우리는 계정 로그인 시스템에서 이용되는 정보들이 무엇이 있는지 확인해 보자.

  1. 계정: 해당 사이트에서 사용자를 구분하기 위해 사용되는 중복되지 않는 식별자를 애기한다.
  2. 패스워드: 계정, 즉 해당 식별자만이 이용할 수 있도록 보호하는 수단으로, 사전에 입력한 문자를 통해 인증하는 방식을 말한다. 보통 패스워드 실패 횟수를 이용한 보안 통제에 이용된다.
  3. 본인 인증: 본인임을 확인하는 수단으로, 소유 인증이 여기에 포함된다. 공인 인증서와 휴대폰 등이 이용되며, 본인만 소유할 수 있다는 장점 때문에 패스워드 변경과 같은 중요한 부분에 이용된다.
  4. 실명 인증: 실제 유효한 주민등록번호인지 확인하는 용도로, 추가 인증으로도 많이 사용된다. 일반적으로 주민등록 번호를 이용해 인증하는 경우를 말한다.
  5. 그림 문자: 영어로 CAPTCHA라고 하며, 사람만이 알아볼 수 있는 그림을 출력해서 자동적으로 계정 로그인을 시도하는 봇(Bot, 자동화 프로그램)을 막는 데 효과적이다. 추가 인증으로 많이 사용된다.
  6. IP: 네트워크로 로그인하는 서비스를 제공할 경우 고객 역시 네트워크를 사용할 수 있는 공인 IP가 필요한데, 이를 통해 로그인을 시도할 수 있다.
  7. 2차 인증: 패스워드 인증 시스템이 취약하여 만들어진 것으로, 패스워드 인증을 통과한 후에 특정 서비스를 이용할 때 추가로 한번 더 인증을 진행하여 보호하는 방식이다. 보안카드, OTP, 지문 인식, 스마트 카드 등이 여기 포함된다. 게임 업체에서 많이 활용되며, 불편하기 때문에 적용률은 낮다.

해킹=돈?!

시간은 금이라고 사람들은 얘기하고 나 역시 그렇다고 생각한다. 또 보안 전문가들은 해킹=돈이라고 흔히 얘기한다. 하지만 난 시간은 금이라는 말에 더 무게를 두고 싶다.

‘해킹=돈’이 말은 틀린 말은 아니다. 실제 공격은 정말 집요하게 이루어진다. 그리고 끝없이 시도한다. 시도와 차단이 반복되는데, 이러한 공격은 그들은 왜 하는 것일까? 바로 돈, 그들 역시 이것을 통해 돈을 벌기 때문에, 많은 노력을 기울이게 된다.

그런데 여기서 중요한 ‘금’이 빠졌다. 해킹=돈, 이 말도 틀린 말은 아니지만, 원래 말이라는 게 아, 어, 하기 나름이다. 하지만, 여기에 더 중요한 시간은 어떤 무엇보다 중요한, 같은 위치에 놓아야 할 정도의 핵심 부분이다. 위험 분석을 할 때 위험 계산을 위험 비용에 횟수나 시간을 곱하도록 되어 있다. 해킹 역시 돈이라면, 해킹으로 얻은 비용(돈)에 들인 시간을 나누어야 할 것이다.

예로 해커가 1시간을 투자해 해킹에 성공하여 100만 개의 계정을 탈취 이를 팔아 100만원을 벌었고, 해커의 월급은 250만원이다. 이는 고용자 입장에서 볼 때, 해커를 근무일수 20일 곱하기 근무시간 8시간을 하였을 때, 160시간 동안 250만원이상을 벌어다 주면 이득이 발생하게 되는데, 100만원을 1시간에 벌었으므로, 큰 이득을 봤다고 할 수 있다.

이 관점에서 이용하면, 어떻게 고객 계정을 보호해야 할 지 답이 나올 것이다. 즉 하루 공격해서 그들이 최소한 계정 해킹을 통해 얻어갈 수 있는 이득을 소량을 만들어, 해킹으로 얻은 이득을 최소화하는 것이다.

해킹이 돈인 지금, 돈벌이가 될 수 없도록 시스템을 구성을 하면 된다. 이제부터 시스템 강화를 어떻게 구성하여야 할지, 그 프로세스를 만들어 보자.

3 어떻게 통제할 것인가?

정상 로그인 이외의 상황을 통제하자.

많은 네트워크 기반 로그인 시스템을 보유하고 있는 업체에서 여러 방식으로 보안 통제를 하고 있을 것이다. 이렇게 적용하기 위해서, 우리는 먼저 정상 이용자를 분석할 필요가 있다.

정상 이용자는 로그인 후, 일정 시간 필요한 정보를 찾거나, 이용을 한 뒤 로그오프를 진행하게 되는데, 이러한 패턴을 분석하여 공격이라고 판단할 수 있는 기준을 정해야 한다. 여기서는 다음과 같은 간단한 가정을 정하였다. “공격? 몇 초, 몇 분 이내에 다량 로그인 시도를 하게 된다.”

바로 이점을 이용하여 로그인 시도를 시간으로 정하여 통제 프로세스를 로그인 시스템에 추가할 것이며, 보안이 강화되었을 때 효과를 생각해 보자.

그럼 어떻게 지연시켜야 할까?

여기서는 다음과 같은 조건을 통해 프로세스를 수립하였다.

  1. 10초 이내에는 로그인할 수 없다.
  2. 1시간 이내인 시도 횟수가 30회 이상이면, 추가 정보(실명 인증, 그림 문자)를 입력 후 로그인할 수 있다.
  3. 1시간 이내 시도 횟수가 30회 이상일 때 패스워드 실패 횟수가 20회 이상이면, 로그인한 IP이서 1시간 이내 로그인 성공한 계정은 본인 인증(소유 인증 포함)을 진행하도록 한다.
  4. 1시간 이내 시도 횟수가 30회 이상일 때 패스워드 실패 횟수가 40회 이상이면, 해당 IP를 블록(차단) IP로 등록하여, 해제할 때까지 추가 정보(실명 인증, 그림 문자) 입력 후 로그인 하도록 할 수 있다.
  5. 동일 ID에 대해 10회 이상 패스워드 실패시, 추가 정보(실명 인증, 그림 문자) 입력 후 로그인할 수 있다.
  6. 블록(차단) IP는 관리자가 설정한 경우 1주일 뒤 해제되며, 4번에 의해 자동으로 설정한 경우 1일 이후 해제된다.
  7. 관리자는 로그인 기록을 확인하여, 수동으로 IP를 차단해 해당 IP는 해제할 때까지 추가 정보(실명 인증, 그림 문자) 입력 후 로그인하도록 할 수 있다.

생각보다 조건은 깔끔하다.

7번을 제외하고는 나머지는 시스템이 자동적으로 진행하도록 함으로써, 최대한 관리자들이 진행하는 작업 비중을 줄이고, 휴먼 에러를 최소화 하도록 하자(관리자도 사람이기 때문에 관리가 허술할 때, 문제가 커질 수 있다).

이 조건의 시간들은 정해진 것이 아님을 명심하기 바란다. 이는 각 사이트, 기업에 맞게 시간을 조절하면 더욱 안정적인 시스템을 만들 수 있다.

이 조건을 프로세스화 하면 아래와 같이 나타낼 수 있다.


[그림 4] 로그인 시도 통제 흐름도

위 그림과 같이 프로세스를 적용하면 1시간 이내에 30회만 정상 로그인이 가능한 구조로, 그 이상 로그인을 시도할 경우 추가 정보를 입력해야 로그인을 할 수 있다(로그인 차단은 10초 이내에만 진행한다).

만약 우리가 위에서 만든 7개 프로세스를 도입하면, 해커의 경우 이 사이트를 24시간 로그인 시도 공격할 경우, 로그인 시도한 IP별로 720개의 계정 정보를 공격 할 수 있다. 실명 인증, 그림 문자는 직접 입력해야 하기 때문에 1000개 이상을 수작업으로 입력하기는 어려우므로 고객 계정의 로그인 시도를 막을 수 있다. 그리고 다수의 IP를 이용해 로그인 시도를 하더라도, 특정 횟수 이상 실패시 해당 IP에서 로그인한 계정들은 본인 인증 프로세스를 거치도록 자동 설정되므로, 해커는 더욱 공격에 어려움을 느끼게 되고, 로그인 시도 IP에서 로그인 성공한 계정 역시 보호할 수 있다.

그래도 해커의 노력으로 1개의 좀비 PC당 최대 공격 성공 개수인 720 개의 계정을 가져갔다고 했을 때, 개인정보를 판매하는 일반적인 가격인 10원으로 환산하면 좀비 PC 1개로 얻는 이득이 1만원 정도의 가치도 되지 않기에 공격 효율을 낮추는 데 효과적이라고 할 수 있다. 여러 사이트에 정보를 판다 하여도, 개별 IP별 로그인 성공, 실패 횟수를 특정횟수 이상인 것에 대해 관리자 모니터링을 할 수 있고, 일정 실패횟수 이상이 되면, 3번 조건에 따라 로그인 성공한 계정에 추가 인증 체계(휴대폰, 공인인증서)를 진행하도록 자동 설정되므로, 계정 구입하는 제삼의 업체에서 구입 가치를 떨어트림과 동시에 물론 로그인 성공한 계정에 해커가 들어오는 것도 매우 힘들어지게 된다.

물론 이 로그인 시도 통제는 일반 이용자들에게 약간의 불편을 줄 수 있다. 1시간에 30번 이상 로그인 시도하는 이용자들에게는 상당히 불편한 시스템이 아닐 수 없다. 하지만 이 30회라는 값은 여기서 사용한 값일 뿐이고, 일반 사용자의 경우 1시간 이내에 30회 로그인 시도를 할 가능성도 적다. 그리고 위 값들은 각 사이트에 맞게 조절 하면 된다.

이해를 돕기 위해 각 주요 확인 지점을 조금 자세히 살펴보자.

  1. 10초 이내 로그인: 이전 로그인 시도 시간과 비교하여 10초 이내인 경우 로그인을 허용하지 않는 조건이다.
  2. 블록(차단) IP 확인: 이는 후속 처리를 위한 것으로, 관리자 페이지에서 관리자가 수동으로 설정하거나, 실패 조건에 의해 자동적으로 설정하여, 공격이 많은 IP에서는 1시간 이후 자동적으로 초기화 되지 않고 지속적으로 추가 정보를 입력하도록 하여, 계정 공격으로부터 고객정보를 보호하는 역할을 한다.
  3. 1시간 이내 로그인: 로그인 통제의 핵심 조건으로 1시간 이내 허용하는 로그인 횟수인 30회 이상 진행하였는지 확인하는 조건이 된다. 이것을 통해 일정 시간 이내 로그인 시도하는 횟수를 로그인 시도한 IP별로 통제할 수 있다.
  4. 20회 이상 로그인 실패: 1시간 이내 이내인 경우 공격성 IP인지를 확인하는 조건으로 공격성 IP라는 조건에 맞으면, 자동으로 해당 IP에서 로그인 성공한 계정에 대해 로그인시 본인 인증을 거쳐야 로그인이 완료되도록 설정을 하는 조건이다. 이를 통해 로그인 성공한 계정들도 자동적으로 보호할 수 있다.
  5. 40회 이상 로그인 실패: 이 조건을 통해 공격 IP의 경우 1시간이 경과하여도 계속 추가 인증을 통해 로그인하도록 한다.

그럼 이제 이러한 시스템을 개발하기 위한 개발 언어와 DBMS 그리고 DB 테이블 구조 등을 정해야 한다. 그리고 각 조건들은 어떻게 코드로 구현가능한지 고민해야 한다. 그럼 본격적인 개발에 들어가보도록 하자.

4 실습 준비

여기에서 사용한 시스템은 테스트 환경으로 생각하기 바란다.

앞서 얘기한 로그인에 보안을 위한 부분에 집중할 예정이다. 그 외 코드와 환경은 그림 혹은 핵심 부분 정도만 짚어보고 넘어갈 예정이다. 구성에 사용된 시스템 환경은 아래와 같다.

MYSQL 5.1: http://www.mysql.com/

IIS6.0: IIS 7.0, 8.0 가능

ASP: Windows 기본 구성요소

Windows 2003: 운영체제(Windows 2008, 2012 가능)

그리고 DB 관리를 위해 아래와 같은 DB 관리도구와 프로그램 편집도구를 사용하였다.

Toad for MySQL: http://www.quest.com/toad-for-mysql/

MySQL Workbench: http://www.mysql.com/products/workbench/

Notepad++: http://notepad-plus-plus.org/


[그림 5] 무료이지만 문서 편집, 프로그램 제작에 편리한 기능을 다수 제공하는 Notepad++

MySQL Workbench는 MySQL에 기본으로 포함된 패키지이다. 관리 기능에 특화되었지만, T-SQL문 작성 기능 역시 우수하여, 굳이 별도의 관리 도구를 설치할 필요가 없을 정도로 편리한 UI, 기능을 제공한다. 필자 역시 작업을 하며 Toad와 Workbench를 병행하며, 함께 사용하였다. 특히 기본 포함 패키지인 만큼 프로시저 제작과 계정 관리 등 여러 영역에서 사용자를 돕는다

[그림 6] MySQL for Windows용 설치시 포함된 SQL 관리 도구

Toad는 DBA들 사이에서 유명한 도구로, T-SQL문 작성에 많은 도움을 받을 수 있다. 더욱이 MySQL 버전에 한하여 무료로 제공하므로 기업 입장에서는 더할 나위 없이 좋은 제품이라 할 수 있다. 굳이 정리하자면, T-SQL문은 Toad가 좋으며, DB 관리 기능은 Workbench가 우수한 것 같다.

[그림 7] MySQL에 한해 무료로 제공하는 Toad for MySQL

이 중 MySQL Workbench는 Toad를 사용하지 않더라도 충분한 T-SQL문 능력을 보여준다. 여기에서 애기하는 환경과 도구는 절대적이지 않으며, 보안 프로세스와 DB만 정해지면, 자바, 아파치 등, 여러 시스템 환경에서 구성이 가능하다. 프로그램 역시 조건과 시간에 민감하므로 이 부분만 해결하면, 어렵지 않게 구성할 수 있다.

그럼 시작에 앞서, 프로그램에서 DB에 접근하는 계정을 따로 생성하여, 해당 계정이 필요한 권한만 설정하여 주기 바란다. 그리고 기존 기본 계정인 root도 변경하여 사용하기 바라며, root 계정은 원격지에서 로그인하지 못하도록 설정하는 게 바람직하다(MySQL은 기본적으로 root는 로컬에서만 로그인이 가능하다).

이렇게 DB 테이블을 만들고 나면, ODBC를 이용할 수 있도록 ODBC에 등록하여야 한다. 다행이 MySQL for Windows 5.1에서는 ODBC용 드라이버를 함께 설치해 주므로 쉽게 ODBC구성을 할 수 있을 것이다.

[그림 8] 생성한 계정을 통해 ODBC 구성

DB 작업시 계정에도 필요한 권한만 주어, 계정 노출시 위험을 줄이도록 하자.

[그림 9] MySQL 계정 생성 및 권한 설정 내용

이제 개발에 앞서 위해 필요한 DB 테이블에 구성을 확인할 차례이다. 필자는 이 로그인 보안 통제 시스템을 위해 아래와 같이 사용자 테이블과 통제 테이블을 작성했다.

[그림 10] 데이터베이스 테이블 구성

login_ip 테이블은 본 로그인 통제의 핵심 테이블이라 할 수 있다. 각 필드에 대해 알아보자

IP: 로그인한 IP를 기록한다.

lastlogintime: 마지막 로그인 시도 시간을 기록한다. 편한 계산을 위해 초단위로 저장하도록 하였다.

count: 시도 횟수를 기록한다.

fcount: 실패 횟수를 기록한다.

block: 차단IP인지 이 부분을 통해 확인, 기록한다.

btime: 차단시 시간을 설정하여, 차후 차단 해제 작업에 활용 한다.

badmin: 관리자가 차단하였는지 확인하기 위한 용도로 활용한다.

login_id 테이블은 로그인 정보가 들어있는 테이블로 해당 로그인 통제에서 필요한 필드만 확인해 보자.

fcount: ID별 패스워드 실패 제한 횟수를 두어 해당 값 이상인 경우, 본인 인증 혹은 추가인증을 진행한다.

forcepw: 공격IP로 탐지된 IP에서 로그인 성공한 계정에 대해 로그인시 이 필드에 값을 넣어 본인인증을 요구하는 조건이 사용하는 필드이다.

lastresult: 공격IP로 탐지된 IP에서 이 필드를 통해 로그인 성공한 계정을 확인할 수 있다.

마지막 id_admin 테이블은 관리자를 위한 테이블로 로그인 성공과 실패를 기록해, 관리자들이 이를 수동으로 조건을 넣고 의심되는 IP를 모니터링 할 수 있도록 만든 테이블이다.

로그인 성공이나 실패시 이 테이블에 정보를 남기게 된다. 이를 이용해 간단한 웹 관리 페이지를 만들어 관리하면 된다.

그리고 여기서 놓치지 말아야 할 점은 바로 차단 IP 해제 조건으로 이 부분은 프로시저 등을 이용하여, 정해놓은 차단 일수 혹은 시간 이후 자동으로 해제하도록 구현하여야 한다.

이제 로그인 통제 프로세스에 필요한 조건과 DB를 설계 하였다 이를 실제 프로그램을 통해 구현을 해보도록 하자.

그럼 이제 테이블 생성 T-SQL문을 통해 DB를 생성할 단계이다. 참고로 DB는 MySQL설치 시 기본 생성되는 test Database를 사용하였다.

createsql.sql
CREATE TABLE id_admin (

time varchar(45) NOT NULL,

id varchar(12) DEFAULT NULL,

ip varchar(45) DEFAULT NULL,

result varchar(45) DEFAULT NULL,

PRIMARY KEY (time)

)

[예제 1] id_admin테이블 생성 T-SQL

createsql.sql
CREATE TABLE login_id (

id varchar(12) NOT NULL DEFAULT ”,

password varchar(12) NOT NULL,

ip varchar(45) DEFAULT NULL,

logintime varchar(45) DEFAULT NULL,

fcount int(4) DEFAULT NULL,

forcepw int(1) DEFAULT NULL,

lastresult int(1) DEFAULT NULL,

PRIMARY KEY (id)

)

[예제 2] login_id테이블 생성 T-SQL

createsql.sql
CREATE TABLE login_ip (

ip varchar(16) NOT NULL DEFAULT ”,

logintime int(12) NOT NULL,

count int(4) NOT NULL,

block int(1) DEFAULT NULL,

fcount int(1) DEFAULT NULL,

btime varchar(45) NOT NULL,

PRIMARY KEY (ip)

)

[예제 3] id_admin테이블 생성 T-SQL

위 T-SQL문을 SQL Query 관리 도구에서 실행하면, 다음과 같이 3개의 테이블이 생성되었음을 확인 할 수 있다.

[그림 11] MySQL Workbench로 확인한 생성된 테이블

이렇게 사전 준비 작업을 마무리했으면 실제 코드를 구현하며, 작동 여부를 각 부분별로 살펴보도록 하자.

5 실전 개발– 웹 부분

로그인 시도 통제는 로그인 페이지에서 사용자 ID와 패스워드를 입력 받으면 동작하게 된다.

통제를 위해 로그인 시도 클라이언트 IP와 날짜 관련된 함수가 사용되는데, 이는 로그인 시도 통제를 시간관점으로 통제하기 때문에 이에 맞도록, 내장 함수를 이용하여 우리가 원하는 값을 도출하여야 한다.

먼저 간단한 사용자 입력을 받아 로그인을 하는 페이지를 만들어 보자.

login.html
<html>

<head>

<meta http-equiv=”Content-Type” content=”text/html; charset=euc-kr”>

<title>로그인 보안 테스트</title>

<style type=”text/css”>

<!–

.input {font-size: 9pt; color:#555555; border:1 solid #cccccc; background-color:#ffffff}

–>

</style>

<script type=”text/javascript”>

<!—

// ID 특수 문자 체크

var p1 = /^[0-9a-z_]*$/i;

function formCheck(){

var frm = document.form;

// 계정 체크

if( !p1.exec(frm.id.value) || frm.id.value.length < 4 ){

alert(“아이디는 4자 이상(숫자, 영문자만 이용가능)으로 입력하여야 합니다!!”);

frm.id.focus();

return false;

}

// 패스워드 공란 체크

if( frm.password.value == “” ){

alert(“비밀번호를 입력하세요!!”);

frm.password.focus();

return false;

}

frm.submit();

}

//–>

</script>

</head>

<body leftmargin=”0″ topmargin=”0″ marginwidth=”0″ marginheight=”0″>

// 로그인 입력 폼과 호출 페이지를 지정한다.

<form name=”form” method=”POST” action=”Check.asp” onSubmit=”return formCheck();”>

<table width=”400″ border=”0″ cellspacing=”0″ cellpadding=”0″>

<tr>

<td height=”35″>ID</td>

<td height=”35″><input name=”id” type=”text” class=”input” size=”25″ maxlength=”24″ tabindex=”1″></td>

<td rowspan=”2″><input type=”submit” value=”Login” border=”0″ tabindex=”3″></td>

</tr>

<tr>

<td height=”35″>PW</td>

<td height=”35″><input name=”password” type=”password” class=”input” size=”27″ maxlength=”27″ tabindex=”2″></td>

</tr>

</table>

<table width=”400″ border=”0″ cellspacing=”0″ cellpadding=”0″>

<tr>

<td height=”5″></td>

</tr>

</table>

</form>

</body>

</html>

[예제 4] 로그인 페이지

위 로그인 페이지를 IIS 메인 디렉토리에 위치시킨 후 인터넷 익스플로러를 이용해 확인하면 다음과 같이 로그인 창이 나타난다.

[그림 12] 간단한 로그인 페이지 완성

이제 로그인 준비는 끝이 났다. 이제부터, 로그인의 보안 프로세스를 연결할 보안 페이지를 만들어 보도록 하자. 먼저 보안 통제를 위해 이용할 ASP의 각 내장 함수의 기능은 다음과 같다.

Now
‘Now 함수를 이용할 경우, 현재 날짜와 시간을 표시한다.
‘출력예
Response.Write Now2011-12-16 오후 11:12:32

Timer

‘Timer 함수를 이용할 경우, 금일 자정을 기준으로 경과한 시간을 초단위로 표현한다.

‘출력예(현재 오전 01:00일 경우)

Response.Write Timer

3600

Datediff

‘Datediff 함수를 이용할 경우, 기준일로부터 경과한 시간을 표현한다. 이용하기 위해서는 비교 함

‘수가 추가로 필요하다. 일, 시, 분, 초등 다양하게 사용할 수 있다.

‘출력예

FDate = CDate(“2011년 1월 1일”)

Response.Write 2011년 1월 1일 부터 지난초: ” & DateDiff(“s”, FDate, Date) & “<BR>”

2011년 1월 1일 부터 지난초: 25642000

그럼 로그인 시도 통제 시스템에서 어떻게 시간 함수를 구하는지 확인해보자.

로그인 시도 통제를 위해서는 로그인 시도를 초단위로 알아야 한다. 그리고, 하루가 지나도 값이 누적해서 계속 상승하여야 하는데, 이는 전날 오후에 로그인하고 다음날 오전에 로그인 하는 경우, 24시간으로 계산시 값이 줄어들어 정상적으로 상황을 알 수 없게 된다(물론 통제 전 날짜를 확인하면 되지만 이는 문제를 더욱 복잡하게 만든다). 따라서 특정일 기준으로 시간 값은 계속 상승하여야, 손 쉽게 우리가 생성하는 조건에 맞도록 구성할 수 있다.

그리고 차후 프로시저 이용을 위해 날짜 출력을 MySQL내부에서 사용하는 함수 구분과 맞춰야 하므로, 내장 함수를 약간 조작하여야 한다.

그럼 로그인 시도에 사용될 함수들을 살펴보자.

check.asp
<%

Function now24(strValue)

now24 = Right(“0″&strValue,2)

End function

id = Trim(request(“id”))

password = Trim(request(“password”))

Tblname1 = “login_id”

Tblname2 = “login_ip”

Tblname3 = “id_admin”

clientip = Request.ServerVariables(“REMOTE_ADDR”)

FirstDate = CDate(“2011년 1월 1일”)

DayTime = DateDiff(“s”, FirstDate, Date)

Storetime = DayTime+Timer

…중략

[예제 5] 로그인 시도 통제를 위한 사용되는 함수들

now24의 경우 ASP 함수의 경우 24시간으로 표시하는 내장함수가 없기 때문에 24시 형식으로 표현하기 위하여 사용되었다. 구현 코드는 아래와 같이 사용한다.

Function now24(strValue)

now24 = Right(“0″&strValue,2)

End function

Response.Write “& now24(hour(time)) &”:”& now24(minute(time)) &”:”& now24(second(time)) &”

‘출력내용 (오후2시22분44초인경우)

14:22:44

id, password: login.htm로 붙어 넣어온 입력값이 된다.

clientip: .ASP의 Request.ServerVariables 기능을 통해 클라이언트 IP정보를 가져올 수 있다. 그 외 아래와 같은 정보를 가져올 수 있으니 참고하기 바란다.

AUTH_TYPE : 인증 타입

CONTENT_LENGTH : 클라이언트로 보내진 바이트 수

CONTENT_TYPE : Request가 POST 타입일 경우, 콘텐트 타입

DOCUMENT : 현재 문서 파일 이름

DOCUMENT_URI : 현재 문서의 가상 경로

DATE_GMT : 현재 날짜, GMT

DATE_LOCAL : 현재 날짜, 로컬

GATEWAY_INTERFACE : 게이트웨이 CGI

LAST_MODIFIED : 문서 최근 수정 날짜

LOGON_USER : 사용자에 대한 윈도우 NT Account

PATH_INFO : 클라이언트에 의해 제공한 경로

PATH_TRANSLATED : 가상 경로를 실제 물리 디렉토리 이름으로 변환한 값

QUERY_STRING : T-SQL문 스트링

QUERY_STRING_UNESCAPED : T-SQL문 스트링 un-escaped version

REMOTE_ADDR : 클라이언트 IP 주소

REMOTE_HOST : 클라이언트 호스트 이름

REMOTE_IDENT : 클라이언트 호스트 이름, RFC931

REMOTE_USER : 클라이언트 사용자 이름,

REQUEST_METHOD : 서버로 보내진 폼 METHOD

SCRIPT_NAME : 실행할 스크립트 혹은 애플리케이션의 이름

SERVER_NAME : 서버의 호스트 이름

SERVER_PORT : 요구를 받을 TCP/IP 포트

SERVER_PORT_SECURE : Encrypt된 포트일 경우 값이 1

SERVER_PROTOCOL : 프로토콜 이름과 버전

SERVER_SOFTWARE : 서버 소프트웨어의 이름과 버전

HTTP_ACCEPT : 브라우저에서 받아들일 수 있는 MIME 타입

HTTP_ACCEPT_LANGUAGE : 클라이언트가 받아들일 수 있는 언어

HTTP_USER_AGENT : 클라이언트가 사용하는 브라우저

HTTP_REFERER : 현재 페이지를 얻고자 할 때 사용한 링크를 담고 있는 URL

HTTP_COOKIE : 클라이언트가 보낸 쿠키

Storetime: 접근 시간을 초로 계산한 값으로, FirstDate와 DayTime은 이를 위해 사용된다. 그런데, DayTime만으로는 오늘날짜의 00시00분00초의 초까지만 계산해 주기 때문에, Storetime 함수를 추가해 오늘날짜부터 현재 시간까지 지난 시간을 초로 더하게 된다.

그럼 로그인과 로그인 시도 통제를 위해 필요한 정보를 DB로부터 T-SQL문을 통해 가져와야 한다. 아래와 같이 T-SQL문을 생성하여 가져 올 수 있다.

QUERY = “SELECT id, password, fcount, forcepw FROM “& Tblname1 &” WHERE id='”& id &”‘”

BLOCK = “SELECT ip, logintime, count, block, fcount FROM “& Tblname2 &” WHERE ip='”& clientip &”‘”

SET rs = dbCon.execute(QUERY)

SET bl = dbCon.execute(BLOCK)

[예제 6] 로그인 및 로그인 시도 관련 정보를 가져오는 T-SQL문

이렇게 함수와 기본 T-SQL문까지 구현하였다. 그럼 각 조건에 맞는 코드를 생성해 보자.

5.1 10초이내 로그인 방지

10초 이내 로그인 방지 관련된 조건문은 간단히 생성할 수 있다.

Login_ip 테이블로부터 기존에 저장된 logintime 필드의 값에 +10을 더한 값보다 현재 값이 작다면, 로그인할 수 없도록 작성하면 된다.

check.asp
…중략
If (bl(“logintime”)+10) > Storetime Thenresponse.write “<script>alert(‘현재 저장된 시간: “& Trim(bl(“logintime”)+10) &”\n 로그인 시도 시간: “& Storetime &”\n너무 빠르게 로그인 시도 하셧습니다!’);history.go(-1);</script>”Else…중략

[예제 7] 10초이내 로그인 비교와 출력 문구

크다, 작다와 같은 ASP의 조건문은 아래와 같은 의미를 지닌다.

= 같다
<> 같지 않다
!= 같지 않다
> 크다
>= 크거나 같다
!> 크지 않다
< 작다
<= 작거나 같다
>= 크거나 같다
!< 작지 않다

[표 1] 조건 연산자

이 조건 연산자는 T-SQL에서도 동일하게 사용되므로, 익혀두기 바란다.

그럼 다시 프로그램으로 돌아와, 우리가 코드 작성에서 기존에 등록되지 않은 IP로 로그인 할 경우 로그인 시도 통제 T-SQL문을 통해 가져올 수 없어, 에러가 발생한다. 따라서 아래와 같은 코드를 추가하여 처음 로그인하는 경우 정상 로그인으로 처리하도록 하자.

check.asp
…중략
If ( bl.bof OR bl.eof ) ThenSQL1 = “INSERT INTO “& Tblname2 &” (ip, logintime, count, badmin) VALUES (‘”& clientip &”‘, ‘”& Storetime &”‘, ‘0’, ‘0’)”dbCon.Execute(SQL1)response.write “<script>alert(‘”& clientip &”는 처음 로그인 시도한 IP입니다.\n 정상 로그인이 가능 합니다(로그인 코드는 생략)!!’);history.go(-1);</script>”

End If

…중략

[예제 8] 처음 시도하는 IP를 등록하는 코드

↓처음 로그인 시도 이후 10초 이내 로그인시도로 차단된다.

[그림 13] 10초 이내 로그인 시도로 인한 차단

–박스 시작—

랜덤 값 사용하기

변화 값을 이용한 Rnd 함수를 이용하여, 정해진 범위 안의 값을 임의로 발생하도록 할 수 있다.

이 함수를 이용해 예측할 수 없도록 하여, 분석을 어렵게 만들 수도 있고, 통제 시스템에 유연성을 만들어 줄 수도 있으므로, 알아두도록 하자(예제 코드에서는 적용하지 않았다).

<%

Dim r, s

s = 15

Randomize

r = Int((s * Rnd) + 1) ‘ 1에서 15까지 무작위 값 발생

Response.Write r

%>

Randomize를 통해 난수 발생기를 초기화하여 새로운 시드값 제공이 가능하다. 생략할 경우 시스템 타이머에서 반환하는 값을 새 시드값으로 사용한다.

–박스 종료–

5.2 블록(차단) IP 확인

이번엔 블록(차단) IP 기능 확인해보자.

이는 해당 DB에 값이 설정되어 있는지 여부를 확인하는 방식으로 조치하였다.

check.asp
…중략
If bl(“block”) = 1 Thenresponse.write “<script>alert(‘블럭 설정된 IP입니다.\n\n”& clientip &”는 추가 정보 입력페이지 호출(코드는 생략)!’);history.go(-1);</script>”Else…중략

[예제 9] 블록(차단) IP 설정 코드

위와 같이 조건에 맞을 경우 추가 정보를 입력하는 페이지를 호출하도록 구성하면 된다. 테스트를 위해 login_ip 테이블의 block 필드에 값을 업데이트 한 후, 로그인 시도를 해보자.

UPDATE test.login_ip SET block=1 WHERE ip=’10.0.2.16′;

↓아래와 같은 로그인 페이지를 추가로 만들어 로그인 요청을 받도록 한다.


[그림 14] 추가 인증을 요구하는 로그인 페이지

26.5.3 1시간 이내 로그인 성공 계정 보호, 공격 IP 설정

이 프로세스에 가장 중요한 부분으로 코드 역시 좀 길다.

1시간 이내인 경우 30회 이상인지, 30회 이상인 경우 로그인 시도 실패 카운트를 확인하도록 되어 있다.

1시간 이내에 30회 이하인 경우에는 로그인 시도 카운트만 증가 시키고, 로그인 진행을 하도록 한다. 그리고 If Then 코드의 특성을 이용하여 조건이 맞을 시에만 실행하고 위 조건을 포함한 추가 조건으로 구성하여야 한다. 해당 코드를 정리하면 다음과 같다.

check.asp
…중략
‘1시간 이내인지 확인한다. 1시간 이내가 아니면 단순 로그인 시도 카운터를 증가 시킨다.
If (bl(“logintime”)+3600) > Storetime Then’30회 이상인지 확인한다. 30회 이상인 경우 추가적인 차단 프로세스를 확인 한다.If (bl(“count”)) > 30 Then

SQL2 = “UPDATE “& Tblname2 &” SET count='”& (bl(“count”)+1) &”‘, logintime='”& Storetime &”‘ WHERE ip='”& clientip &”‘”

dbCon.Execute (SQL2)

‘실패카운터가 40회 이상인지 확인한다. 40회 이상이면 로그인을 성공했던 계정에 본인인증을 설정하고, 현 IP에 대해 계속 추가정보를 입력하여 로그인 하도록 설정 한다.

If (bl(“fcount”)) > 40 Then

SQL4 = “UPDATE “& Tblname2 &” SET block=’1′, btime='”& Date &”‘, badmin=0 WHERE ip='”& clientip &”‘”

dbCon.Execute (SQL4)

SQL5 = “UPDATE “& Tblname1 &” SET forcepw=’1’ WHERE ip='”& clientip &”‘ AND logintime='”& Date &” “& now24(hour(time)) &”‘ And lastresult=’1′”

dbCon.Execute (SQL5)

response.write “<script>alert(‘현재 시도 횟수:”& bl(“count”) &”\n\n 실패 횟수:”& bl(“fcount”) &”\n\n”& clientip &”로 30회 이상, 실패 20회 이상으로\n\n 로그인 성공 계정 본인인증 설정\n\n IP 차단 설정\n\n그림문자,실명인증페이지 호출(코드는 생략)!!’);history.go(-1);</script>”

End If

‘로그인 시도 실패 횟수가 20회 이상인지 확인한다. 로그인을 성공했던 계정에 대해 본인인증을 설정 한다. 그리고 현재 로그인 시도에 대해서 추가 정보를 입력하여 로그인 하도록 한다.

If (bl(“fcount”)) > 20 Then

SQL3 = “UPDATE “& Tblname1 &” SET forcepw=’1′ WHERE ip='”& clientip &”‘ AND logintime='”& Date &” “& now24(hour(time)) &”‘ And lastresult=’1′”

dbCon.Execute (SQL3)

response.write “<script>alert(‘현재 시도 횟수:”& bl(“count”) &”\n\n 실패 횟수:”& bl(“fcount”) &”\n\n”& clientip &”로 30회 이상, 실패 20회 이상으로\n\n 로그인 성공 계정 본인인증 설정\n\n그림문자,실명인증페이지 호출(코드는 생략)!!’);history.go(-1);</script>”

End If

’30회 이상인 상태이므로 추가 정보를 입력해 로그인 하도록 한다.

response.write “<script>alert(‘현재 시도 횟수:”& bl(“count”) &”\n\n”& clientip &”로 30회 이상으로 추가 정보 입력\n\n그림문자,실명인증페이지 호출(코드는 생략)!!’);history.go(-1);</script>”

Else

SQL6 = “UPDATE “& Tblname2 &” SET count='”& (bl(“count”)+1) &”‘, logintime='”& Storetime &”‘ WHERE ip='”& clientip &”‘”

dbCon.Execute (SQL6)

response.write “현재 횟수”& bl(“count”) &” “& clientip &” 1시간 이내 30회 이하로 로그인 하셧습니다!–>”

End If

…중략

[예제 10] 1시간 이내 로그인 시도인 경우 확인하는 조건 코드 전체

그럼 하나씩 확인해 보도록 하자. 1시간 이내 30회 로그인 시도 이후 로그인 상황 설정 후 테스트 해보도록 하자.

UPDATE test.login_ip SET count=31, ‘block’=0 WHERE ip=’10.0.2.16′;

그리고 10.0.2.16 IP의 클라이언트로 로그인을 시도하면 아래와 같이 로그인이 바로 진행되지 않고, 2차 인증을 진행해야 하는 로그인할 수 있다.

[그림 15] 30회 이상 실패시 추가인증 페이지 호출

1시간 이내 30회 로그인 시도, 로그인 실패가 20회 시도하였을 상황은 재현해 보자. 임의의 계정을 로그인 성공하였다는 상황을 만들기 위해 아래와 같이 계정을 추가 설정한다.

UPDATE test.login_ip SETcount=31, ‘block’=0, fcount=21 WHERE ip=’10.0.2.16′;

INSERT INTO test.login_id (id, password, ip, logintime, lastresult) VALUES (‘test3’, ‘12342134’, ‘10.0.2.16’, ‘2011-12-19 14’, 1);

이제 해당 IP로 로그인 실패를 20회 이상 진행되었다는 상황으로 해당 IP로 로그인 성공한 모든 계정은 본인 인증을 진행하도록 하여야 한다. 그리고 현재 로그인 시도 역시 2차 인증은 진행하여야 한다.

[그림 16] 20회 이상인 경우 로그인 성공계정에 본인인증을 설정

추가인증 페이지 호출과 동시에, 로그인 IP에서 같은 시간 로그인 성공한 계정에 대해 강제 본인 인증을 자동으로 설정되게 된다.

[그림 17] 10.0.2.16으로 동일시간에 로그인 성공한 계정을 강제 본인 인증으로 설정한 화면

이제 마지막으로 공격 IP로 판단하는 40회 이상 실패 상황을 아래와 같이 만들어 테스트 해보자.

UPDATE test.login_ip SET fcount=41 WHERE ip=’10.0.2.16′;

이때는 앞 단계와 조치는 같으나 한가지 추가되는 상황이 현재 IP에 대해 블랙 IP로 설정되어, 블랙 IP로 지정되면, 무조건 2차 인증을 진행하여야 로그인 할 수 있도록 설정된다.

[그림 18] 40회 이후인 경우 로그인 성공계정에 본인인증을 설정, IP 차단

추가 인증 페이지 호출과 동시에, 로그인 IP에서 같은 시간 로그인 성공한 계정에 대해 강제 본인 인증을 자동으로 설정하고, 해당 IP를 블록(차단) IP 로 등록하게 된다. 이후 다시 해당 IP로 로그인 시도하면 차단된 IP로 설정되었음을 확인할 수 있다.

[그림 19] 재 로그인 시도시 차단된 IP

이와 같은 프로세스로 인해 자동적으로 공격이 발생하는 IP에 대해, 차단과 보호를 진행할 수 있다.

[그림 20] login_ip 테이블의 10.0.2.16 IP를 자동을 블록(차단) IP 설정

1시간 이후 로그인 시도한 경우 로그인 시도와 해당 IP로 로그인 시도중 로그인 실패 카운트를 초기화 해준다(단 계정별 패스워드 실패 카운트는 유지된다).

check.asp
SQL7 = “UPDATE “& Tblname2 &” SET logintime='”& Storetime &”‘, fcount=’0′, count=’1’ WHERE ip='”& clientip &”‘”

dbCon.Execute (SQL7)

[예제 11] 1시간 이후 로그인의 경우 카운트를 초기화해주는 조건

즉 한 시간 이후에 로그인하게 되면, 통제가 풀리게 된다.

[그림 21] 1시간 이후 로그인 시도시 카운트 초기화

여기서부터는 일반적인 사이트에서도 적용되어 있는 방식으로 계정 패스워드 실패 횟수에 대한 통제 방식이다. 로그인 처리 중 진행하는 프로세스로, 관리자 테이블 기록과 본인 인증 처리, 해당 계정 패스워드 실패 횟수 처리에 대한 코드를 보도록 하자.

check.asp
…중략
If ( rs.bof OR rs.eof ) ThenSQL8 = “INSERT INTO “& Tblname3 &” (time, id, ip, result) VALUES (‘”& Date &” “& now24(hour(time)) &”:”& now24(minute(time)) &”:”& now24(second(time)) &”‘, ‘”&Trim(request(“id”)) &”‘, ‘”& clientip &”‘, ‘Fail’)”dbCon.Execute(SQL8)response.write “<script>alert(‘존재하지 않는 아이디입니다.!\n\n아이디를 확인하세요!’);history.go(-1);</script>”

Else

If rs(“fcount”) > 10 Then

response.write “<script>alert(‘패스워드를 “& rs(“fcount”) &” 횟 이상 실패하였습니다.\n\n 추가 정보를 입력하여야 합니다.\n\n그림문자,실명인증페이지 호출(코드는 생략)!!’);history.go(-1);</script>”

Else

If Trim(rs(“password”)) <> password Then

SQL9 = “INSERT INTO “& Tblname3 &” (time, id, ip, result) VALUES (‘”& Date &” “& now24(hour(time)) &”:”& now24(minute(time)) &”:”& now24(second(time)) &”‘, ‘”& Trim(request(“id”)) &”‘, ‘”& clientip &”‘, ‘Fail’)”

dbCon.Execute(SQL9)

SQL10 = “UPDATE “& Tblname1 &” SET fcount='”& (rs(“fcount”)+1) &”‘ WHERE id='”& id &”‘”

dbCon.Execute (SQL10)

response.write “<script>alert(‘비밀번호가 틀립니다.\n\n비밀번호를 확인해 주세요!’);history.go(-1);</script>”

Else

If rs(“forcepw”) = 1 Then

response.write “<script>alert(‘공격 IP로 로그인된것으로 의심되는 계정입니다.\n 본인 인증을 입력하여야 합니다\n\n휴대폰인증,공인인증서입력페이지 호출(코드는 생략)!!’);history.go(-1);</script>”

Else

SQL11 = “INSERT INTO “& Tblname3 &” (time, id, ip, result) VALUES (‘”& Date &” “& now24(hour(time)) &”:”& now24(minute(time)) &”:”& now24(second(time)) &”‘, ‘”&Trim(request(“id”)) &”‘, ‘”& clientip &”‘, ‘Success’)”

dbCon.Execute (SQL11)

session(“id”) = trim(rs(“id”))

SQL12 = “UPDATE “& Tblname1 &” SET ip='”& clientip &”‘, fcount=’0’, logintime='”& Date &” “& now24(hour(time)) &”‘, lastresult=’1’ WHERE id='”& session(“id”) &”‘”

dbCon.Execute (SQL12)

rs.close

Set rs= Nothing

bl.close

Set bl= Nothing

dbCon.Close

Set dbCon= Nothing

response.write “로그인 되셨습니다”

End If

End If

End If

End If

…중략

[예제 12] 로그인 진행 코드에도 조건 설정된다

그럼 패스워드 실패 통제 동작 여부 확인을 위해 임의로 패스워드 실패 카운터를 11회로 변경해 테스트를 진행해 보자. 아래는 패스워드 실패 횟수 설정 T-SQL문이다.

UPDATE test.login_id SET fcount=11 WHERE id=’test1′;

[그림 22] 10회 이상 해당 계정에 대한 로그인 실패시 추가 정보를 입력하도록 한다

단 계정에 따른 패스워드 실패는 10회 이전 해당 계정으로 로그인 성공시 패스워드 실패 횟수를 초기화 하도록 하여야 한다. 초기화 해주지 않게 되면, 해당 사용자는 어느 순간부터 계속 추가 정보를 입력하고 로그인하여야 한다.

check.asp
…중략
SQL12 = “UPDATE “& Tblname1 &” SET ip='”& clientip &”‘, fcount=’0′, logintime='”& Date &” “& now24(hour(time)) &”‘, lastresult=’1’ WHERE id='”& session(“id”) &”‘”…중략

[예제 13] 로그인 성공시 패스워드 실패 횟수를 초기화하게 된다

그리고 본인 인증 설정도 정상적으로 동작하는지 확인해 보자. 다음은 본인 인증을 통해 로그인 하도록 설정 T-SQL문이다.

UPDATE test.login_id SET forcepw=1 WHERE id=’test1′;

이후 test 계정으로 로그인을 시도해보자.

[그림 23] 현 인증 체계중 강력한 본인인증을 통해 로그인 진행

이 역시 마찬가지로, 본인 인증을 통해 로그인 성공 시 해당 필드 값을 초기화 해주어야 함을 잊지 말기 바란다.

관리자들을 위해 로그인 성공과 실패 관련 관리자 페이지를 별도로 만들어, 관리자들이 공격으로 의심되는 IP에 대해 IP 차단을 설정할 수 있도록 구성하면, 로그인 시도 통제 프로세스는 완료된다(관리자 페이지 작성에 대해서는 여기서 다루지 않겠다).


[그림 24] 로그인 성공, 실패를 확인할 수 있는 id_admin 테이블

일정 횟수 이상 로그인 시도한 IP에 대해 조사하여 사용한다면 유용할 것으로 판단된다.

SELECT count(*) id, ip from id_admin WHERE time >= DATE(CURDATE()) GROUP BY ip;

[오늘 날짜 로그인 시도 횟수 확인]

SELECT count(*) id, ip from id_admin WHERE time LIKE ‘2011-12-19%’ GROUP BY ip;

[특정 날짜 로그인 시도 횟수 확인]

SELECT count(*) id, ip from id_admin GROUP BY ip;

[전체 로그인 횟수 확인]

이를 뷰 테이블로 만들어서 특정 횟수 이상인 값만 뽑는 프로시저를 만들어서 사용해도 좋고, 맡고 있는 사이트의 입맛에 맞도록 제작해 보기 바란다.

6 실전 개발하기 – 저장 프로시저 부분

이렇게 로그인 시도 통제 관련 코드까지 알아 보았다.

우리가 구성한 모든 프로세스에는 차단을 해제해 줄 수 있는 코드가 함께 들어 있거나, 추가인증 페이지에서 구성해주면 된다. 단, 공격 IP로 구분되어 장시간 차단이 필요한 블록(차단) IP의 경우 사용자가 아닌 서버에서 업데이트 해줘야 하므로 이를 프로시저를 등록하여 자동적으로 구성해 보도록 하자. 프로그램이 자동적으로 등록한 차단IP에 대해서는 1일 이후, 관리자가 등록한 IP에 대해서는 7일 이후 자동으로 해제해 줄 수 있는 프로시저를 만들어 보겠다.

unlockday1-7.sql
CREATE PROCEDURE test.unlock1day ()

BEGIN

SET @1day := DATE_ADD(DATE(CURDATE()), INTERVAL -1 DAY);

UPDATE login_ip SET block=0, btime=0 WHERE btime < @1day AND block=1 AND badmin=0;

END

CREATE DEFINER=juhan@localhost PROCEDURE unlock7day()

BEGIN

SET @7day := DATE_ADD(DATE(CURDATE()), INTERVAL -7 DAY);

UPDATE login_ip SET block=0, btime=0, badmin=0 WHERE btime <= @7day AND block=1 AND badmin=1;

END

[예제 14] IP 차단 자동해제 프로시저

IP 차단시 btime에 현재 날짜를 입력하여, 해당 입력 날짜로부터 경과 시간 이상인 IP에 대해 해제해 주게 된다.

위 프로시저를 윈도우 운영체제에 예약작업으로 등록하여, 자동 실행 할 수 있도록 만들어 보자.

mysql -h127.0.0.1 -ujuhan -psjsj11 -Dtest <unlockday.sql

[start.bat]

CALL 명령을 통해 저장된 프로시저를 호출할 수 있다.

unlockday.sql
call unlock1day();

call unlock7day();

[unlockday.sql]

위에서 작성한 프로시저와 명령문이 작동하는 확인을 위해 아래와 같이 코드를 입력하였다. 블록(차단) IP 해제를 테스트를 위한 T-SQL문이다.

UPDATE test.login_ip SET block=1, btime=’2011-12-19′ WHERE ip=’10.0.2.18′;

UPDATE test.login_ip SET block=1, btime=’2011-12-18′ WHERE ip=’127.0.0.1′;

UPDATE test.login_ip SET block=1, badmin=1, btime=’2011-12-18′ WHERE ip=’10.0.2.1′;

UPDATE test.login_ip SET block=1, badmin=1, btime=’2011-12-10′ WHERE ip=’127.0.0.1′;

위에서 주의 깊게 봐야 할 부분은, 관리자가 등록한 IP로써 현재 2011-12-19으로 1주일 이상 지난IP인 127.0.0.1은 해제 되어야 하고, 1일 경과한 10.0.2.1과, 금일 등록된 10.0.2.18은 유지되어야 정상 작동된다고 할 수 있다.

↓프로시저 실행 결과 아래와 같이 처리 된다.

[그림 25] 프로시저 실행 전, 후 변화된 login_ip 테이블

실행 결과 금일 자동 등록된 IP와 어제 관리자가 등록한 IP를 제외하고 정상적으로 초기화 된 것 확인할 수 있다. 이를 매일 오전 00:00에 실행하도록 시스템 예약 작업에 등록을 하게 되면, 자동 해제가 마무리된다.

[그림 26] 윈도우 예약된 작업에 프로시저 등록

이렇게 로그인 시도 통제를 위한 짧고 간단한 내용이지만, 이를 통해 우리가 보호해야 하는 영역 대해 고민해야 할 부분이 무엇인지, 더 넓은 영역을 함께 고민할 수 있었으면 좋겠다. 그리고 우리의 보안 영역이 너무 역분석에 집중되어 있지 않은지 다시 한번 뒤돌아 봐야 할 때가 아닌가 싶다.

이미 여러 사이트들이 여러 가지로 자신만의 방법으로 영역을 보호하고 있지만, 완벽하다 할 수 없고, 지속적인 개선작업을 통해 앞으로 나아갈 수 있다고 생각한다. 여기에서 애기한 내용 역시 완벽한 것이 아니므로 자신의 사이트에 맞게 개선하고, 분석한다면 더욱 효과적일 것이다.

그리고 보안이라는 말이 모든 분야에 포함됨을 잊지 말자. 물리적 공간, 문서, 음악, 동영상 등, 보안에 분야는 광범위한 만큼 보안은 투자도 중요하지만, 관심이 더 중요하다.

그리고 이 코드는 웹 프로그래머가 봤을 때 어려운 코드가 아니고, 나 역시 전문 웹 프로그래머가 아닌 상황에서도 일주일이 채 걸리지 않음을 보아, 적용 난이도가 높은 것은 아니다. 단지 필요 이유와 구성 방안에 대해 해당 프로그래머를 이해하고 설득시키는 것이 더 중요하다. 이것이 보안이 앞으로 가야 할 뱡향이 아닌가 라는 생각이 든다.

Facebook Comments

Leave A Reply

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.