IgnatiusHeo

구현단계 보안약점 제거 기준-반복된 인증시도 제한 기능 부재 본문

자격/SW보안약점진단원

구현단계 보안약점 제거 기준-반복된 인증시도 제한 기능 부재

Ignatius Heo 2023. 7. 6. 13:46

작성일: 230706

 

※ 본 게시글은 학습 목적으로 행정안전부·KISA의 소프트웨어 보안약점 진단 가이드, 소프트웨어 개발보안 가이드를 참고하여 작성하였습니다.

 

정리 내용: 소프트웨어 보안약점 진단 가이드(400~405p)

구분 - 보안기능
설계단계 - 인증 수행 제한
https://cryptocurrencyclub.tistory.com/101
개요
일정 시간 내에 여러 번의 인증을 시도하여도 계정잠금 또는 추가 인증 방법 등의 충분한 조치가 수행되지 않는 경우, 공격자는 예상 ID와 비밀번호들을 사전(Dictionary)으로 만들고 무차별 대입(brute force)하여 로그인 성공 및 권한획득이 가능하다.

진단 세부사항
(설계단계)
 로그인 기능 구현 시, 인증시도 횟수를 제한하고, 초과된 인증시도에 대해 인증제한 정책을 적용해야 한다. 로그인 기능에 인증시도 횟수를 제한하도록 설계되어 있는지 확인한다.
  ㅇ  로그인 시도 횟수(5회 이내) 제한 정책이 설계 시 반영되었는지 확인
  ㅇ  인증 실패 횟수 정보를 관리하기 위해 영속성이 있는 저장장치(DB, 파일 등)에 인증시도 정보가 저장되도록 설계되어 있는지 확인
  ㅇ  인증 실패 제한 횟수 초과 시 계정 잠금, 추가정보 요구 등 제한 정책 설계 여부 확인
  ㅇ  제한된 횟수를 초과한 로그인 시도가 제한되는지를 점검하기 위한 테스트계획 수립 여부 확인
     - 로그인 실패를 발생시킬 입력값 사용 → 실패 시 제한 정책 적용 여부 확인 → 영속성 있는 저장장치에 기록 여부 확인
 
 ② 실패한 인증시도에 대한 정보를 로깅하여 인증시도 실패가 추적될 수 있게 해야 한다. 로그인 기능에 인증시도 실패 로그를 기록하도록 설계되어 있는지 확인한다.
  ㅇ  사용자ID, 로그인 실패 횟수, 로그인 시도 시간, IP주소, 계정 상태정보 등이 로깅정보에 포함되도록 설계되어 있는지 확인
  ㅇ  초과된 인증시도에 대한 테스트 계획의 수립 여부 확인
  ㅇ  초과된 인증시도에 대한 로깅의 정상 수행 점검을 위한 테스트 계획 수립 여부 확인
보안대책
(구현단계)
인증시도 횟수를 적절한 횟수로 제한하고 설정된 인증실패 횟수를 초과했을 경우 계정을 잠금하거나 추가적인 인증과정을 거쳐서 시스템에 접근이 가능하도록 한다.
진단방법
(구현단계)
인증을 위한 함수를 호출하는 경우, 이 함수의 호출 횟수를 확인하고 함수의 호출을 제한하는 코드가 존재하는지 확인한다. 그렇지 않은 경우는 취약하다고 판단한다.

 

다. 코드예제

 

ㅇ 분석

1: private static final String SERVER_IP = "127.0.0.1";
2: private static final int SERVER_PORT = 8080;
3: private static final int FAIL = -1;
4: public void login() {
5: String username = null;
6: String password = null;
7: Socket socket = null;
8: in t result = FAIL;
9: try {
10: socket = new Socket(SERVER_IP, SERVER_PORT);
//인증 실패에 대해 제한을 두지 않아 안전하지 않다.
11: while (result == FAIL) {
12: ...
13: result = verifyUser(username, password);
14: }
15: }

ㅇ 내용

1. verifyUser 실패에 따른 카운트 변수를 넣으면 될듯

 

ㅇ 수정

1: private static final String SERVER_IP = "127.0.0.1";
2: private static final int SERVER_PORT = 8080;
3: private static final int FAIL = -1;
4: private static final int MAX_ATTEMPTS = 5;
5: public void login() {
6: String username = null;
7: String password = null;
8: Socket socket = null;
9: int result = FAIL;
10: int count = 0;
11: try {
12: socket = new Socket(SERVER_IP, SERVER_PORT);
//인증 실패 및 시도 횟수에 제한을 두어 안전하다.
13: while (result == FAIL && count < MAX_ATTEMPTS) {
14: ...
15: result = verifyUser(username, password);
16: count++;
17: }
18: }

ㅇ 내용

1. 여긴 5회 제한을 넣었음


ㅇ 분석

//로그인 실패 시 아무런 제약이 없음
1: override protected void OnLoginError(EventArgs e)
2: {
3: //do nothing
4: }

ㅇ 내용

1. 이것도 마찬가지로 카운트

 

ㅇ 수정

1: override protected void OnLoginError(EventArgs e)
2: {
// 연속적인 사용자 인증 시도에 대한 횟수를 제한
3: if(ViewState["LoginErrors"] == null)
4: ViewState["LoginErrors"] = 0;
5: int ErrorCount = (int)ViewState["LoginErrors"] + 1;
6: ViewState["LoginErrors"] = ErrorCount;
7: if((ErrorCount > 3) && Login1.PasswordRecoveryUrl !=
string.Empty)
8: Response.Redirect(Login1.PasswordRecoveryUrl);
9: }

ㅇ 내용

1. 3회로 제한함

 


ㅇ 분석

1: int validateUser(char *host, int port) {
2: int socket = openSocketConnection(host, port);
3: if (socket < 0) {
4: printf("Unable to open socket connection");
5: return(FAIL);
6: }
7: int isValidUser = 0;
8: char nm[NAME_SIZE];
9: char pw[PSWD_SIZE];
// 인증시도 횟수를 제한하고 있지 않음
10: while (isValidUser==0) {
11: if (getNextMsg(socket, nm, NAME_SIZE) > 0) {
12: if (getNextMsg(socket, pw, PSWD_SIZE) > 0) {
13: isValidUser = AuthenticateUser(nm, pw);
14: }
15: }
16: }
17: return(SUCCESS);
18:}

ㅇ 내용

1. 제한X

 

ㅇ 수정

1: #define MAX_ATTEMPTS 5
2: int validateUser(char *host, int port) {
3: ......
// 연속적인 사용자 인증 시도에 대한 횟수를 제한
4: int count = 0;
5: while ((isValidUser==0) && (count<MAX_ATTEMPTS)) {
6: if (getNextMsg(socket, nm, NAME_SIZE) > 0) {
7: if (getNextMsg(socket, pw, PSWD_SIZE) > 0) {
8: isValidUser = AuthenticateUser(nm, pw);
9: }
10: }
11: count++;
12: }
13: if (isValidUser) {
14: return(SUCCESS);
15: } else {
16: return(FAIL);
17: }
18:}

ㅇ 내용

1. 제한O 5회

 

끝.