유형 | 보안기능 |
보안약점 | 반복된 인증시도 제한 기능 부재 |
개요 |
일정 시간 내에 여러 번의 인증을 시도하여도 계정잠금 또는 추가 인증 방법 등의 충분한 조치가 수행되지 않는 경우, 공격자는 예상 ID와 비밀번호들을 사전(Dictionary)으로 만들고 무차별 대입(bruteforce)하여 로그인 성공 및 권한획득이 가능하다.
|
보안대책 |
인증시도 횟수를 적절한 횟수로 제한하고 설정된 인증실패 횟수를 초과했을 경우 계정을 잠금하거나 추가적인 인증과정을 거쳐서 시스템에 접근이 가능하도록 한다.
|
진단방법 |
인증을 위한 함수를 호출하는 경우, 이 함수의 호출 횟수를 확인하고 함수의 호출을 제한하는 코드가 존재하는지 확인한다.
그렇지 않은 경우는 취약하다고 판단한다.
|
연관된 설계단계 기준 | 인증 수행 제한 |
코드예제
● 안전하지 않은 코드 예 (Java)
private static final String SERVER_IP = "127.0.0.1";
private static final int SERVER_PORT = 8080;
private static final int FAIL = -1;
public void login() {
String username = null;
String password = null;
Socket socket = null;
in t result = FAIL;
try {
socket = new Socket(SERVER_IP, SERVER_PORT);
// 인증 실패에 대해 제한을 두지 않아 안전하지 않다.
while (result == FAIL) {
...
result = verifyUser(username, password);
}
}
● 안전한 코드 예 (Java)
private static final String SERVER_IP = "127.0.0.1";
private static final int SERVER_PORT = 8080;
private static final int FAIL = -1;
private static final int MAX_ATTEMPTS = 5;
public void login() {
String username = null;
String password = null;
Socket socket = null;
int result = FAIL;
int count = 0;
try {
socket = new Socket(SERVER_IP, SERVER_PORT);
// 인증 실패 및 시도 횟수에 제한을 두어 안전하다.
while (result == FAIL && count < MAX_ATTEMPTS) {
...
result = verifyUser(username, password);
count++;
}
}
● 안전하지 않은 코드 예 (C#)
// 로그인 실패 시 아무런 제약이 없음
override protected void OnLoginError(EventArgs e) {
//do nothing
}
● 안전한 코드 예 (C#)
override protected void OnLoginError(EventArgs e) {
// 연속적인 사용자 인증 시도에 대한 횟수를 제한
if(ViewState["LoginErrors"] == null)
ViewState["LoginErrors"] = 0;
int ErrorCount = (int)ViewState["LoginErrors"] + 1;
ViewState["LoginErrors"] = ErrorCount;
if((ErrorCount > 3) && Login1.PasswordRecoveryUrl != string.Empty)
Response.Redirect(Login1.PasswordRecoveryUrl);
}
● 안전하지 않은 코드 예 (C)
int validateUser(char *host, int port) {
int socket = openSocketConnection(host, port);
if (socket < 0) {
printf("Unable to open socket connection");
return(FAIL);
}
int isValidUser = 0;
char nm[NAME_SIZE];
char pw[PSWD_SIZE];
// 인증시도 횟수를 제한하고 있지 않음
while (isValidUser==0) {
if (getNextMsg(socket, nm, NAME_SIZE) > 0) {
if (getNextMsg(socket, pw, PSWD_SIZE) > 0) {
isValidUser = AuthenticateUser(nm, pw);
}
}
}
return(SUCCESS);
}
● 안전한 코드 예 (C)
#define MAX_ATTEMPTS 5
int validateUser(char *host, int port) {
......
// 연속적인 사용자 인증 시도에 대한 횟수를 제한
int count = 0;
while ((isValidUser==0) && (count<MAX_ATTEMPTS)) {
if (getNextMsg(socket, nm, NAME_SIZE) > 0) {
if (getNextMsg(socket, pw, PSWD_SIZE) > 0) {
isValidUser = AuthenticateUser(nm, pw);
}
}
count++;
}
if (isValidUser) {
return(SUCCESS);
} else {
return(FAIL);
}
}
진단방법
인증을 위한 함수를 호출하는 경우, 이 함수의 호출 횟수를 확인하고 함수의 호출을 제한하는 코드가 존재하는지 확인한다.
그렇지 않은 경우는 취약하다고 판단한다.
● 정탐코드
int validateUser(char *host, int port) {
int socket = openSocketConnection(host, port);
if (socket < 0) {
printf(“Unable to open socket connection”);
return(FAIL);
}
int isValidUser = 0;
char username[USERNAME_SIZE];
char password[PASSWORD_SIZE];
while (isValidUser == 0) {
if (getNextMessage(socket, username, USERNAME_SIZE) > 0) {
if (getNextMessage(socket, password, PASSWORD_SIZE) > 0) {
isValidUser = AuthenticateUser(username, password);
}
}
}
return(SUCCESS);
}
인증을 시도를 할 때, 인증 시도에 대한 제한 없이 반복문 안에서 계속 인증 시도를 하는 코드이다. 인증 시도 회수에 대한 검사 루틴이 존재하지 않으므로 보안약점이 존재하는 코드라고 진단할 수 있다.
'소프트웨어(SW) 보안약점 진단원 > 구현단계 보안약점 제거 기준' 카테고리의 다른 글
구현단계 보안약점 기준 - 경쟁조건: 검사시점과 사용시점(TOCTOU) (0) | 2025.06.04 |
---|---|
구현단계 보안약점 기준 - 신뢰할 수 없는 데이터의 역직렬화 (0) | 2025.06.04 |
구현단계 보안약점 기준 - 무결성 검사 없는 코드 다운로드 (0) | 2025.06.04 |
구현단계 보안약점 기준 - 솔트 없이 일방향 해쉬 함수 사용 (1) | 2025.06.04 |
구현단계 보안약점 기준 - 주석문 안에 포함된 시스템 주요정보 (1) | 2025.06.03 |