Refactor Summernote initialization for consistency and improved readability
This commit is contained in:
@@ -15,12 +15,9 @@ class RequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
// GS인증 크로스사이트스크립트 보안성 문제로 XSS 공격을 방지하기 위한 악성 스크립트 패턴 정의.
|
||||
// 2025.05.27 패턴 추가
|
||||
// 2025.12.30 src 패턴 수정 - 화이트리스트 방식 (http, https, data:image/ 만 허용)
|
||||
private static final Pattern[] PATTERNS = new Pattern[] {
|
||||
Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
|
||||
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
|
||||
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
|
||||
Pattern.compile("<script(.*?)>",
|
||||
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
|
||||
@@ -46,6 +43,16 @@ class RequestWrapper extends HttpServletRequestWrapper {
|
||||
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)
|
||||
};
|
||||
|
||||
// src 속성 화이트리스트 패턴 - data:image/만 허용
|
||||
private static final Pattern SRC_ATTR_PATTERN = Pattern.compile(
|
||||
"(src\\s*=\\s*)([\"'])([^\"']*?)\\2",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
// 허용되는 src 값 패턴 (화이트리스트) - data:image/만 허용
|
||||
private static final Pattern ALLOWED_SRC_PATTERN = Pattern.compile(
|
||||
"^data:image/.*",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
|
||||
public RequestWrapper(HttpServletRequest servletRequest) {
|
||||
super(servletRequest);
|
||||
@@ -123,6 +130,10 @@ class RequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
// script 문자열을 완전히 제거
|
||||
value = value.replaceAll("(?i)\\bscript\\b", "");
|
||||
|
||||
// src 속성 화이트리스트 필터링 - 허용된 프로토콜만 통과
|
||||
value = filterSrcAttribute(value);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
value = convertChars(value, sb);
|
||||
@@ -133,6 +144,37 @@ class RequestWrapper extends HttpServletRequestWrapper {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* src 속성을 화이트리스트 방식으로 필터링
|
||||
* 허용: data:image/ (Base64 이미지)
|
||||
* 비허용: 그 외 모든 프로토콜
|
||||
*/
|
||||
private String filterSrcAttribute(String value) {
|
||||
if (value == null || !value.toLowerCase().contains("src")) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Matcher matcher = SRC_ATTR_PATTERN.matcher(value);
|
||||
StringBuffer result = new StringBuffer();
|
||||
|
||||
while (matcher.find()) {
|
||||
String srcPrefix = matcher.group(1); // src=
|
||||
String quote = matcher.group(2); // " 또는 '
|
||||
String srcValue = matcher.group(3); // src 값
|
||||
|
||||
// 빈 값이거나 화이트리스트에 매칭되면 유지
|
||||
if (srcValue.isEmpty() || ALLOWED_SRC_PATTERN.matcher(srcValue).matches()) {
|
||||
matcher.appendReplacement(result, Matcher.quoteReplacement(srcPrefix + quote + srcValue + quote));
|
||||
} else {
|
||||
// 허용되지 않는 프로토콜은 src="" 로 대체
|
||||
matcher.appendReplacement(result, Matcher.quoteReplacement(srcPrefix + quote + quote));
|
||||
}
|
||||
}
|
||||
matcher.appendTail(result);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
// '(', ')', '"' 문자는 getMethod()가 "get"일 때만 변환됨.
|
||||
// 이는 gridData에서 사용되는 큰따옴표(")와 변환 함수에서 사용하는 괄호('(', ')')의 처리를 위함.
|
||||
private String convertChars(String value, StringBuilder sb) {
|
||||
|
||||
Reference in New Issue
Block a user