7. 🔒 보안 가이드
7.1 보안 개요
홍익인간CMS는 다양한 보안 위협으로부터 시스템을 보호하기 위한 여러 보안 기능을 제공합니다. 이 장에서는 홍익인간CMS의 현재 구현된 보안 기능과 추가로 지원 가능한 기능, 그리고 개발 시 준수해야 할 보안 가이드라인을 설명합니다.
7.1.1 보안 아키텍처
홍익인간CMS의 보안 아키텍처는 다음과 같은 계층으로 구성되어 있습니다:
현재 구현된 보안 기능
- HTTP 보안 헤더 설정
- XSS 방지 필터
- 기본 암호화/복호화 (AES, SHA-256)
- 개인정보 접근 이력 관리
- 세션 관리
- 입력값 검증 유틸리티 (HumanValidatorUtil)
지원 가능한 보안 기능
- Spring Security 기반 인증
- 역할 기반 접근 제어(RBAC)
- CSRF 방지
- 고급 암호화 기법(BCrypt, PBKDF2)
- Bean Validation을 통한 입력값 검증
보안 영역
- 인증 및 권한 관리
- 데이터 보안
- 애플리케이션 보안
- 로깅 및 감사
7.2 현재 구현된 보안 기능
7.2.1 XSS(Cross-Site Scripting) 방지
홍익인간CMS는 XSS 공격을 방지하기 위한 필터를 제공합니다. 이 필터는 사용자 입력값에서 악성 스크립트를 제거하여 XSS 공격을 방지합니다.
주요 기능
- HTML 태그 필터링
- 사용자 입력값 검증
- 출력값 이스케이프 처리
XSSWebFilter.java - 실제 구현된 코드
public class XSSWebFilter implements Filter {
// ...
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// ...
if (isRequestCheck) {
// 파라미터에 특수문자 포함 시 제거
chain.doFilter(new HTMLTagFilterRequestWrapper(req), response);
} else {
chain.doFilter(request, response);
}
// ...
}
}
실제 구현된 XSS 필터 설정
<filter>
<filter-name>XSSWebFilter</filter-name>
<filter-class>humanframe.web.filter.XSSWebFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>XSSWebFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
7.2.2 암호화/복호화
홍익인간CMS는 기본적인 암호화/복호화 기능을 제공합니다. 이 기능은 개인정보 및 비밀번호 등 민감한 정보를 보호하는 데 사용됩니다.
주요 기능
- ARIA 암호화/복호화
- SHA-256 기반 비밀번호 암호화
- AES-256 암호화/복호화 (HumanAES256Util)
- 설정 기반 암호화 키 관리
HumanCryptoServiceImpl.java - 실제 구현된 코드
@Service("humanCryptoService")
public class HumanCryptoServiceImpl extends HumanAbstractServiceImpl implements HumanCryptoService {
@Resource(name="propertiesService")
private EgovPropertyService properties;
@Resource(name="ARIACryptoService")
private EgovCryptoService cryptoService;
@Resource(name="passwordEncoder")
public EgovPasswordEncoder egovPasswordEncoder;
@Override
public String encrypt(String str) throws Exception {
byte[] encrypted = cryptoService.encrypt(str.getBytes("UTF-8"), properties.getString("CRYPTO_KEY"));
String encryptStr = new String(Base64.encodeBase64(encrypted));
return encryptStr;
}
@Override
public String decrypt(String str) throws Exception {
byte[] decrypted = cryptoService.decrypt(Base64.decodeBase64(str.getBytes()), properties.getString("CRYPTO_KEY"));
return new String(decrypted, "UTF-8");
}
/**
* 비밀번호를 암호화하는 기능(복호화가 되면 안되므로 SHA-256 인코딩 방식 적용)
*/
@Override
public String encryptPassword(String password, String id) throws Exception {
if (password == null) {
return "";
}
byte[] hashValue = null; // 해쉬값
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.reset();
md.update(id.getBytes());
hashValue = md.digest(password.getBytes());
return new String(Base64.encodeBase64(hashValue));
}
}
7.2.3 개인정보 접근 이력 관리
홍익인간CMS는 개인정보 접근 이력을 관리하는 기능을 제공합니다. 이 기능은 개인정보보호법 준수를 위해 중요합니다.
주요 기능
- 개인정보 접근 이력 기록
- 메뉴별 개인정보 접근 여부 설정
- 접근 유형별 로깅(조회, 수정, 삭제 등)
AdminPrivacyAspect.java - 실제 구현된 코드
@Aspect
@Order(2)
@Component
public class AdminPrivacyAspect {
@Resource(name = "mngPrivacyService")
private MngPrivacyService mngPrivacyService;
// 관리자 권한 체크
@Pointcut("execution(* humanframe.backoffice..Admin*Controller.form(..))"
+ "|| execution(* humanframe.backoffice..Admin*Controller.list(..))"
+ "|| execution(* humanframe.backoffice..Admin*Controller.view(..))"
+ "|| execution(* humanframe.backoffice..Admin*Controller.action(..))"
+ "|| execution(* humanframe.web.controller.admin..Admin*Controller.list(..))"
+ "|| execution(* humanframe.web.controller.admin..Admin*Controller.view(..))"
+ "|| execution(* humanframe.web.controller.admin..Admin*Controller.form(..))"
+ "|| execution(* humanframe.web.controller.admin..Admin*Controller.action(..))")
private void checkAdminPrivacy() {}
@Before(value = "checkAdminPrivacy()")
private void beforeCheckAdminPrivacy(JoinPoint joinPoint) throws Exception {
HttpServletRequest request = null;
for (Object o : joinPoint.getArgs()) {
if (o instanceof HttpServletRequest)
request = (HttpServletRequest)o;
}
if(request != null) {
// 개인정보 접근이력 저장
String logTxt = "IP:" + request.getRemoteAddr() + ", " + className + "." + methodName;
for(MngMenuVO sessMenuVO : mngrSession.getMngMenuList()){
if(sessMenuVO.getMenuUrl().contains(request.getServletPath().substring(0,request.getServletPath().lastIndexOf("/")))){
if(sessMenuVO.getPrivacyAt().equals("Y")) {
mngPrivacyService.createMngPriacyAccess(logTy, request.getServletPath(), logTxt);
}
}
}
}
}
}
7.2.4 HTTP 보안 헤더 설정
홍익인간CMS는 HTTP 보안 헤더를 통해 기본적인 웹 보안을 강화합니다.
주요 기능
- 쿠키 보안 설정(HttpOnly)
- 제한된 HTTP 메소드 설정
- 세션 관리
실제 구현된 HTTP 보안 설정
<session-config>
<session-timeout>60</session-timeout>
<cookie-config>
<http-only>true</http-only> <!-- 서버 요청이 있을 때에만 쿠키가 전송되도록 설정 -->
<!-- <secure>true</secure> --> <!-- SSL 통신 채널 연결 시에만 쿠키를 전송 하도록 설정 -->
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
<security-constraint>
<display-name></display-name>
<web-resource-collection>
<web-resource-name>restricted methods</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>TRACE</http-method>
<http-method>DELETE</http-method>
<http-method>PUT</http-method>
<http-method>HEAD</http-method>
<http-method>OPTIONS</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>nobody</role-name>
</auth-constraint>
</security-constraint>
7.2.5 입력값 검증 유틸리티
홍익인간CMS는 humanframe.core 라이브러리를 통해 다양한 입력값 검증 유틸리티를 제공합니다.
주요 기능
- 이메일, URL 형식 검증
- 숫자, 알파벳, 한글 등 문자 유형 검증
- 비밀번호 복잡성 검증
- 문자열 길이 검증
HumanValidatorUtil.java - 실제 코드 일부
public class HumanValidatorUtil {
// 정규식 패턴
final static private String pattern_alpha = "^[A-Za-z]*$";
final static private String pattern_numeric = "^[0-9]*$";
final static private String pattern_korean = "^[ㄱ-ㅎ|가-힣]*$";
final static private String pattern_email = "^[-A-Za-z0-9_]+[-A-Za-z0-9_.]*[@]{1}[-A-Za-z0-9_]+[-A-Za-z0-9_.]*[.]{1}[A-Za-z]{2,5}$";
final static private String pattern_url = "^(https?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
final static private String pattern_invalid_password = "^(?=.*?[a-zA-Z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,25}$";
// 이메일 검증
public static boolean isEmail(String value) {
return nullChecker(5, value);
}
// URL 검증
public static boolean isUrl(String value) {
return nullChecker(6, value);
}
// 비밀번호 복잡성 검증
public static boolean isValidPassword(String value){
return nullChecker(10, value);
}
// 알파벳+숫자 조합 검증
public static boolean isAlphaNumeric(String value) {
if (!nullChecker(value)) {
boolean bReturn = true;
char[] cArr = value.toCharArray();
int alphaLen = 0;
int numericLen = 0;
for (char c : cArr) {
if (isAlpha(String.valueOf(c))) {
alphaLen++;
}
if (isNumeric(String.valueOf(c))) {
numericLen++;
}
}
if ((alphaLen == 0) || (numericLen == 0) || (cArr.length != (alphaLen + numericLen))){
bReturn = false;
}
return bReturn;
} else {
return false;
}
}
}
7.3 보안 코딩 규칙
홍익인간CMS 개발 시 준수해야 할 보안 코딩 규칙은 다음과 같습니다.
7.3.1 오류 메시지 출력 정보 노출 방지
오류 메시지에 민감한 정보가 노출되지 않도록 주의해야 합니다.
잘못된 예시
try {
// 데이터베이스 작업
} catch (SQLException e) {
e.printStackTrace(); // 오류 스택 트레이스 노출
return "데이터베이스 오류: " + e.getMessage(); // 오류 메시지 노출
}
올바른 예시
try {
// 데이터베이스 작업
} catch (SQLException e) {
logger.error("데이터베이스 오류", e); // 로그에만 기록
return "시스템 오류가 발생했습니다. 관리자에게 문의하세요."; // 일반적인 오류 메시지
}
7.3.2 오류 상황 대응 부재 방지
모든 예외 상황에 대한 적절한 처리가 필요합니다.
잘못된 예시
public void processData(String data) {
// 예외 처리 없음
int value = Integer.parseInt(data); // NumberFormatException 발생 가능
// 처리 로직
}
올바른 예시
public void processData(String data) {
try {
int value = Integer.parseInt(data);
// 처리 로직
} catch (NumberFormatException e) {
logger.error("숫자 변환 오류", e);
throw new BusinessException("유효하지 않은 데이터입니다.");
}
}
7.3.3 적절하지 않은 예외 처리 방지
예외를 무시하거나 부적절하게 처리하지 않도록 주의해야 합니다.
잘못된 예시
try {
// 파일 작업
} catch (Exception e) {
// 아무 처리 없음 (예외 무시)
}
올바른 예시
try {
// 파일 작업
} catch (IOException e) {
logger.error("파일 처리 오류", e);
throw new BusinessException("파일 처리 중 오류가 발생했습니다.");
}
7.3.4 구체적인 예외 처리
예외 처리 시 일반적인 Exception 클래스보다 구체적인 예외 클래스를 사용해야 합니다.
잘못된 예시
try {
// 파일 읽기, 네트워크 요청, 데이터베이스 쿼리 등 다양한 작업
} catch (Exception e) {
logger.error("오류 발생", e);
throw new RuntimeException("처리 중 오류가 발생했습니다.");
}
올바른 예시
try {
// 파일 읽기 작업
} catch (FileNotFoundException e) {
logger.error("파일을 찾을 수 없음", e);
throw new BusinessException("요청하신 파일을 찾을 수 없습니다.");
} catch (IOException e) {
logger.error("파일 읽기 오류", e);
throw new BusinessException("파일 읽기 중 오류가 발생했습니다.");
} catch (SQLException e) {
logger.error("데이터베이스 오류", e);
throw new SystemException("데이터베이스 처리 중 오류가 발생했습니다.");
} catch (RuntimeException e) {
logger.error("런타임 오류", e);
throw new SystemException("시스템 처리 중 오류가 발생했습니다.");
}
구체적인 예외 처리의 장점
- 명확한 오류 원인 파악: 구체적인 예외 클래스를 사용하면 오류의 원인을 더 명확하게 파악할 수 있습니다.
- 적절한 대응 가능: 예외 유형에 따라 적절한 대응 방법을 선택할 수 있습니다.
- 코드 가독성 향상: 어떤 예외가 발생할 수 있는지 명확하게 표현되어 코드의 가독성이 향상됩니다.
- 유지보수성 향상: 특정 예외 처리 로직을 수정할 때 다른 예외 처리에 영향을 주지 않습니다.
- 보안 강화: 예외 유형에 따라 적절한 오류 메시지를 제공하여 민감한 정보 노출을 방지할 수 있습니다.
7.3.5 SQL 인젝션 방지
SQL 인젝션 공격을 방지하기 위한 코딩 규칙을 준수해야 합니다. 홍익인간CMS는 MyBatis를 사용하여 SQL 쿼리를 관리하므로, 파라미터 바인딩을 통해 SQL 인젝션을 방지할 수 있습니다.
잘못된 예시
public BbsVO selectBbsVulnerable(String bbsNo) {
String sqlId = "bbs.selectBbs";
String dynamicSql = sqlId + "_" + bbsNo; // 위험: 사용자 입력이 SQL ID에 직접 포함됨
return (BbsVO) selectOne(dynamicSql);
}
올바른 예시 (MyBatis 매핑 활용)
public BbsVO selectBbs(int bbsNo) {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("bbsNo", bbsNo);
return (BbsVO) selectOne("bbs.selectBbs", paramMap);
}
<select id="bbs.selectBbs" parameterType="java.util.Map" resultType="humanframe.web.vo.BbsVO">
SELECT
bbs_no,
title,
content,
reg_dt
FROM
tn_bbs
WHERE
bbs_no = #{bbsNo}
</select>
7.3.6 코딩 컨벤션 준수
일관된 코딩 스타일을 유지하기 위해 코딩 컨벤션을 준수해야 합니다.
주요 규칙
- 클래스, 메소드, 변수 등의 명명 규칙 준수
- 들여쓰기 및 공백 사용 규칙 준수
- 주석 작성 규칙 준수
- 패키지 구조 규칙 준수
7.4 보안 취약점 점검 및 관리
7.4.1 보안 취약점 점검 항목
다음과 같은 보안 취약점 점검 항목을 주기적으로 확인하는 것이 좋습니다:
🔐 인증 및 권한 관리
- 인증 우회 취약점
- 권한 검증 누락
- 세션 관리 취약점
✅ 입력값 검증
- XSS 취약점
- SQL 인젝션 취약점
- 명령어 인젝션 취약점
📤 출력값 처리
- 민감 정보 노출
- 오류 메시지 노출
📁 파일 처리
- 경로 조작 취약점
- 파일 업로드 취약점
🔒 암호화
- 취약한 암호화 알고리즘 사용
- 암호화 키 관리 취약점
7.4.2 보안 패치 및 업데이트
홍익인간CMS의 보안을 유지하기 위해 정기적인 보안 패치 및 업데이트가 필요합니다.
패치 적용 절차
🔍 보안 취약점 확인
시스템에 영향을 줄 수 있는 보안 취약점 확인
📋 패치 내용 검토
패치의 내용과 영향 범위 검토
🧪 테스트 환경 적용
테스트 환경에서 패치 적용 및 테스트
🚀 운영 환경 적용
운영 환경에 패치 적용
📊 결과 모니터링
패치 적용 결과 모니터링
의존성 라이브러리 관리
📋 라이브러리 목록 관리
의존성 라이브러리 목록 관리
🔍 취약점 정보 모니터링
보안 취약점 정보 모니터링
🔄 라이브러리 업데이트
취약점이 발견된 라이브러리 업데이트
🧪 호환성 테스트
업데이트 후 호환성 테스트
7.5 결론
홍익인간CMS는 기본적인 보안 기능을 제공하며, 개발자는 필요에 따라 추가적인 보안 기능을 구현할 수 있습니다. 현재 구현된 기능으로는 XSS 방지 필터, 암호화/복호화, 개인정보 접근 이력 관리, HTTP 보안 헤더 설정, 입력값 검증 유틸리티 등이 있으며, 이를 통해 기본적인 보안 요구사항을 충족할 수 있습니다.
추가적인 보안 강화가 필요한 경우, Spring Security 기반 인증, 역할 기반 접근 제어, CSRF 방지, 고급 암호화 기법 등을 구현할 수 있습니다. 이러한 기능들은 humanframe.core 라이브러리를 확장하여 구현하거나, 외부 라이브러리를 활용하여 구현할 수 있습니다.
중요사항
보안은 지속적인 관리와 개선이 필요한 영역이므로, 정기적인 보안 점검과 업데이트를 통해 시스템의 안전성을 유지하는 것이 중요합니다. 개발자는 이 매뉴얼에서 제시하는 보안 코딩 규칙을 준수하고, 필요에 따라 추가적인 보안 기능을 구현하여 홍익인간CMS의 보안을 강화할 수 있습니다.