소프트웨어 개발보안 가이드 분석(2021) : 취약한 비밀번호 허용
사용자에게 강한 패스워드 조합규칙을 요구하지 않으면, 사용자 계정이 취약하게 되며, 사전 공격(Dictionary Attack), 무차별 대입공격(Brute-Force Attack) 등에 취약할 수 있다.
소프트웨어 개발보안가이드(2021), 한국인터넷진흥원
취약한 비밀번호로 인한 사고 사례
2012년에는 한 소셜 미디어 플랫폼에서 대규모 데이터 유출 사고가 발생했습니다. 이 사고의 주요 원인 중 하나는 사용자들이 약한 비밀번호(예: "123456", "password" 등)를 사용함으로써 해커들이 브루트포스(무차별 대입 공격) 방법으로 쉽게 접근할 수 있었기 때문입니다. 이러한 유출로 인해 수백만 사용자의 개인정보가 위험에 노출되었고, 이는 해당 기업의 명성과 신뢰도에 치명적인 타격을 주었습니다.
위 사례와 같은 데이터 유출을 방지하기 위해서는 사용자에게 강력한 비밀번호를 설정하도록 권장하는 것이 중요합니다. 강력한 비밀번호는 다음과 같은 조합을 포함하여 사용되어야 합니다.
한국인터넷진흥원에서는 가이드를 통해 "안전한 비밀번호"와 "안전하지 않은 비밀번호"에 대한 예시들을 통해 패스워드 보안정책의 기준을 제시하고 있습니다.
* 안전한 비밀번호에 대한 기준
- 다양한 유형의 문자를 조합한 비밀번호: 숫자, 대소문자, 특수문자 등을 조합
- 8자 이상의 길이
- 10자리 이상의 길이를 권장하며 최대 4자리까지 동일한 문자 반복 가능
- 숫자나 특수문자를 전체 길이의 절반까지 사용 가능
* 안전하지 않은 비밀번호
- 통상적인 패턴을 갖는 비밀번호: 예를 들어 연속된 숫자 ('123123')
- 키보드 상의 연속된 위치에 있는 문자들의 조합 ('qwerty')
- 사용자 개인 정보에 기반한 단어나 숫자: 예를 들어 사용자의 이름, 생년월일, 주소, 전화번호 등
- 사용자 ID를 포함한 비밀번호
- 사용자 ID가 'kisa'인 경우에 'kisa1' 등으로 쉽게 유추할 수 있는 비밀번호
- 특정 문화나 사회에서 자주 사용되는 단어나 구절: 예를 들어 '안녕하세요', 'love12' 등
- 웹사이트 이름이나 업체 이름을 포함하는 비밀번호
- 사이트, 기업명, 마켓 이름 등 특정 회사와 연관이 있는 단어
- 특정 영화나 캐릭터 이름을 포함한 비밀번호: 예를 들어 '스타워즈', 'ironman1' 등
- 사전에 정의된 순서대로의 디폴트 비밀번호: 예를 들어 '0000', 'password'
- 화살표 키 배열과 같은, 오른쪽이나 왼쪽으로 순차적으로 나열된 키보드 패턴
취약한 코드 및 안전한 코드 예제
* 취약한 코드 예제
가입자가 입력한 비밀번호에 대한 복잡도 검증 없이 가입 승인 처리를 수행하고 있습니다.
String id = request.getParameter("id");
String pass = request.getParameter("pass");
UserVo userVO = new UserVo(id, pass);
// 비밀번호의 자릿수, 특수문자 포함 여부 등 복잡도를 체크하지 않고 등록
String result = registerDAO.register(userVO);
* 안전한 코드 예제
사용자 계정을 보호하기 위해 가입 시, 비밀번호 복잡도 검증 후 가입 승인처리를 수행합니다.
String id = request.getParameter("id");
String pass = request.getParameter("pass");
// 비밀번호에 자릿수, 특수문자 포함 여부 등의 복잡도를 체크하고 등록하게 한다.
Pattern pattern = Pattern.compile("((?=.*[a-zA-Z])(?=.*[0-9@#$%]).{8,})");
Matcher matcher = pattern.matcher(pass);
if (!matcher.matches()) {
return "비밀번호 조합규칙 오류";
}
UserVo userVO = new UserVo(id, pass);
String result = registerDAO.register(userVO);
SW개발보안가이드의 예제 코드를 응용하여, 회원 등록 과정에서 패스워드 정책을 검증하기 위한 Java 코드는 다음과 같습니다. 이 코드는 패스워드 정책을 준수하는지 확인하는 로직을 포함하고 있습니다.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PasswordPolicyValidator {
private static final Pattern PASSWORD_PATTERN =
Pattern.compile("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$");
public static void main(String[] args) {
String password = "UserPassword123!";
if (validatePassword(password)) {
System.out.println("Password is valid and meets the policy requirements.");
// 회원 등록 로직 수행
} else {
System.out.println("Password does not meet the policy requirements.");
}
}
public static boolean validatePassword(String password) {
Matcher matcher = PASSWORD_PATTERN.matcher(password);
return matcher.matches();
}
}
이 패스워드 정책 검증 로직은 다음 규칙을 따릅니다:
최소 한 개의 숫자 포함 ((?=.*[0-9]))
최소 한 개의 소문자 포함 ((?=.*[a-z]))
최소 한 개의 대문자 포함 ((?=.*[A-Z]))
최소 한 개의 특수 문자 포함 ((?=.*[@#$%^&+=]))
공백이 없어야 함 ((?=\\S+$))
최소 8자 이상 (.{8,})