서버에러
운영서버에 소스코드 반영 후 IP로 접속시 정상 작동하나 도메인으로 접속시 JSON을 클라이언트에서 받아오지 못하는 이슈 발생
확인해보니 controller에서 content를 application/json로 지정한 부분을 지우니 String으로 Response를 받아옴
= json이나 jsonObject자체를 받아오지 못한다고 해석
응답은 넘어오나 한글이 깨지는 이슈가 발생
서버에서 Response에 대한 content를 text/plain(text/html)으로 지정하고 charset을 UTF-8로 지정 진행
@SuppressWarnings("unchecked")
// @RequestMapping(value = "/path/geoJson", produces ="application/json; charset=utf-8")
@RequestMapping(value = "/path/geoJson", produces ="text/html; charset=utf-8")
public @ResponseBody String selectData (HttpServletRequest request, HttpServletResponse response,
@RequestParam HashMap hMap, Model model, SearchCriteria cri, HttpSession session)
throws IOException, Exception {
...
return jsonObject.toJSONString();
}
하지만 서버만 인코딩을 변경하면 클라이언트 단에서 이슈가 발생할수도 있다고 하여 클라이언트단에서도 UTF-8로 인코딩하고 content는 json으로 변경하도록 수정
function useAjaxData(value){
$.ajax({
method: "GET",
url: "/prefix/path/geoJson?data="+response,
contentType: "application/json",
dataType: "json",
// }).done(function (obj) {
// var dataValue = JSON.parse(obj);
}).done(function (dataValue) {
...
});
});
...
}
하지만 한글이 깨지는 것은 수정했지만 response에서 변형이 일어나는 것을 확인
방법은
1. 서버의 환경설정을 변경(이 방법이 근본적인 해결이라고 생각)
2. controller에서 jsonObject.toJSONString이 아닌 Entity로 반환하는 것으로 수정


하지만 사용하는 JSON데이터가 고정적으로 정해진 데이터이므로 JSON응답을 아예 JSON파일로 resource에서 받아 해당 json파일을 불러오는 방식으로 진행
보안이 취약한 단점은 있으나 담당자가 해당 방법으로 라도 선진행을 요청하여 해당 방법으로 진행
function useAjaxData(value){
$.ajax({
method: "GET",
url: "/prefix/path/geoJson?data="+response+".json",
contentType: "application/json",
dataType: "json",
}).done(function (dataValue) {
...
});
});
...
}
하지만 근본적으로 한글이 깨지는 것도 아닌 숫자가 ******로 변형된다는 것이 아직도 이해가 되지 않는다.
XSS 방지
URL을 통한 XSS 공격은 lucy-xss-servlet-filter를 이용해 막고있다.
하지만 CKEditor5를 사용하는데 해당 에디터를 이용해 XSS 취약점에 대한 보완작업을 진행했다.
public static String getReplace(String str) {
str = str.replaceAll("<br>", "\n");
str = str.replaceAll(">", ">");
str = str.replaceAll("<", "<");
str = str.replaceAll(""", "\"");
str = str.replaceAll(" ", " ");
str = str.replaceAll("&", "&");
str = str.replaceAll("<script>", "");
str = str.replaceAll("</script>", "");
str = str.replaceAll("(?i)<script>", "");
str = str.replaceAll("(?i)</script>", "");
str = str.replaceAll("[(?i)o][(?i)n][\\w]*[=$]", "");
str = str.replaceAll("[o][n][\\w]*[=$]", "");
str = str.replaceAll("[aA][lL][eE][rR][tT][(][\\S]*[);$]", "");
str = str.replaceAll("eval\\((.*)\\)", "");
str = str.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
str = str.replaceAll("script", "");
return str;
}
기존에 문자열 변환을 통해 어느 정도 수정은 하고있었지만 단순하기도 하고, 이벤트에 대한 방어가 전혀 되지 않았다.
또한 자체적인 필터(관련 문서 : 링크)도 있다고는 하지만 그것만 의존하면 안되고 서버단에서도 확인하고 방지하는 것이 유익하다.
따라서 XssUtil을 생성하는 방식으로 구현했다.
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.stereotype.Component;
import java.util.regex.Pattern;
@Slf4j
@Component(value="xssUtil")
public class XssUtil {
public String preventXss(String attack) {
String cleaned = this.cleanXss(attack);
return cleaned;
}
private String cleanXss(String text) {
Pattern onEventPattern = Pattern.compile("(<\\p{Z}?[^>]+\\p{Z})" +
"(on[\\w\\p{Z}]+?=\\p{Z}*'[^']*'" +
"|on[\\w\\p{Z}]+?=\\p{Z}*\"[^\"]*\"" +
"|on[\\w\\p{Z}]+?=[^>]*)" +
"([^>]*>)",
Pattern.CASE_INSENSITIVE); // 대소문자 구분없이 필터링
String unescaped = StringEscapeUtils.unescapeHtml4(StringEscapeUtils.unescapeXml(text));
String eventRemoved = onEventPattern.matcher(unescaped).replaceAll("$1$3");
// 제거할 태그 목록 정의 (예: script, iframe, frame(set), eval, javascript)
Pattern blacklist = Pattern.compile("script|iframe|frame(set)|eval|javascript",
Pattern.CASE_INSENSITIVE);
return blacklist.matcher(eventRemoved).replaceAll("");
/* // 화이트리스트
* // 허용된 태그 목록 정의 (예: p, a, img)
* Pattern whitelist = Pattern.compile("<(?!/?(p|a|img)(\\s|>))[^>]+>", Pattern.CASE_INSENSITIVE);
*
* // 허용되지 않은 태그와 속성 제거
* String safeOutput = whitelist.matcher(eventRemoved).replaceAll("");
*/
}
}
'Backend' 카테고리의 다른 글
JMeter 부하테스트 (0) | 2025.01.14 |
---|---|
240729 회고 (0) | 2024.07.29 |
application.properties vs application.yml (0) | 2024.02.19 |
H2 Manual (0) | 2024.02.19 |
DTO / VO / Entity (0) | 2024.02.19 |