1. SQL 인젝션 (SQL Injection) 방어
악의적인 SQL 구문을 입력해 DB 데이터를 탈취하거나 조작하는 공격입니다.
✅ 체크리스트
- MyBatis XML 매퍼에서 파라미터를 받을 때 ${} 기호를 사용하고 있지 않은가?
- ORDER BY 절이나 테이블명을 동적으로 바꿀 때, 사용자 입력을 그대로 연결(Concatenation)하고 있지 않은가?
🛠️ 구현 방법
① 반드시 #{} (PreparedStatement) 사용하기 MyBatis에서 #{}을 사용하면 내부적으로 입력값을 문자열(String)로 안전하게 바인딩하여 쿼리 구조 자체를 변경할 수 없게 만듭니다.
SELECT * FROM wtr_api_artcl_info WHERE api_nm = '${apiNm}'
SELECT * FROM wtr_api_artcl_info WHERE api_nm = #{apiNm}
② 동적 쿼리(ORDER BY 등)는 화이트리스트 검증 ORDER BY 구문에는 #{}을 쓸 수 없어서 어쩔 수 없이 ${}를 써야 할 때가 있습니다. 이때는 입력값을 그대로 넣지 말고, 서버 단에서 허용된 문자열(화이트리스트)인지 무조건 체크해야 합니다.
// Controller나 Service에서 검증
String sortType = commandParm.getSortType();
// 허용된 정렬 기준이 아니면 기본값으로 강제 변경
if (!"clot_cnt".equals(sortType) && !"api_nm".equals(sortType)) {
sortType = "api_no"; // 기본값
}
2. 크로스 사이트 스크립팅 (XSS) 방어
게시판이나 입력창에 <script>alert('해킹')</script> 같은 태그를 넣어, 다른 사용자가 조회할 때 악성 스크립트가 실행되게 만드는 공격입니다.
✅ 체크리스트
- 화면(JSP 등)에 데이터를 출력할 때 HTML 태그가 그대로 렌더링되도록 방치하고 있지 않은가?
- API(JSON) 통신 시, 클라이언트에서 보낸 < , > 기호가 그대로 DB에 들어가고 있는가?
🛠️ 구현 방법
① JSP 화면 출력 시 이스케이프 처리 만약 JSP를 사용 중이라면 데이터 출력 시 무조건 <c:out>을 사용하세요. < 기호를 <로 자동 변환하여 스크립트 실행을 막아줍니다.
<div>${apiInfo.apiNm}</div>
<div><c:out value="${apiInfo.apiNm}" /></div>
② JSON API 통신 시 Jackson XSS 처리 (가장 중요) 앞서 작성하셨던 @RequestBody나 @ResponseBody를 통한 API 통신의 경우, JSON 데이터를 변환할 때 스크립트 태그를 무력화하는 MessageConverter를 설정해야 합니다.
가장 널리 쓰이는 방법은 네이버에서 만든 Lucy XSS Filter를 적용하거나, Jackson ObjectMapper를 커스터마이징하는 것입니다.
Jackson ObjectMapper 커스텀 예시 (설정 파일에 추가):
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
// HTML 문자를 이스케이프 처리하는 모듈 등록 (별도 클래스 구현 필요)
objectMapper.getFactory().setCharacterEscapes(new HtmlCharacterEscapes());
converter.setObjectMapper(objectMapper);
converters.add(converter);
}
}
③ 정규식(Regex)을 통한 입력 원천 차단 가장 강력한 프론트엔드/백엔드 방어입니다. VO 객체에서 아예 특수문자나 영문 스크립트가 들어오지 못하도록 @Pattern으로 막아버립니다.
public class PrecipitationStationVO {
// 한글, 영문, 숫자, 공백만 허용 (<, >, script 등 원천 차단)
@Pattern(regexp = "^[a-zA-Z0-9가-힣\\s]*$", message = "특수문자는 입력할 수 없습니다.")
private String searchKeyword;
}
💡 요약하자면
- SQL 방어: MyBatis에서 무조건 #{} 쓴다.
- XSS 방어: 입력받을 때 정규식으로 특수문자를 튕겨내거나, 출력할 때 <c:out> / ObjectMapper로 문자열을 치환한다.