
소프트웨어 개발보안 가이드 분석(2021) : 취약한 비밀번호 허용
사용자에게 강한 패스워드 조합규칙을 요구하지 않으면, 사용자 계정이 취약하게 되며, 사전 공격(Dictionary Attack), 무차별 대입공격(Brute-Force Attack) 등에 취약할 수 있다.
소프트웨어 개발보안가이드(2021), 한국인터넷진흥원
취약한 비밀번호로 인한 사고 사례
2012년에는 한 소셜 미디어 플랫폼에서 대규모 데이터 유출 사고가 발생했습니다. 이 사고의 주요 원인 중 하나는 사용자들이 약한 비밀번호(예: "123456", "password" 등)를 사용함으로써 해커들이 브루트포스(무차별 대입 공격) 방법으로 쉽게 접근할 수 있었기 때문입니다. 이러한 유출로 인해 수백만 사용자의 개인정보가 위험에 노출되었고, 이는 해당 기업의 명성과 신뢰도에 치명적인 타격을 주었습니다.
_wnLBMHf.png)
위 사례와 같은 데이터 유출을 방지하기 위해서는 사용자에게 강력한 비밀번호를 설정하도록 권장하는 것이 중요합니다. 강력한 비밀번호는 다음과 같은 조합을 포함하여 사용되어야 합니다.
_ZUi5MF6.png)
한국인터넷진흥원에서는 가이드를 통해 "안전한 비밀번호"와 "안전하지 않은 비밀번호"에 대한 예시들을 통해 패스워드 보안정책의 기준을 제시하고 있습니다.
* 안전한 비밀번호에 대한 기준
- 다양한 유형의 문자를 조합한 비밀번호: 숫자, 대소문자, 특수문자 등을 조합
- 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,})