게시글 제목, 내용에 대한 특수문자(태그포함) 및 XSS 처리 통합자료관과 통일성있게 변경 처리
This commit is contained in:
parent
22f543a91a
commit
3c29a91a59
@ -93,8 +93,8 @@ public class ArticleVO extends PagingVO {
|
|||||||
return attachFiles.size();
|
return attachFiles.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUnescapedContent() {
|
public String getSanitizedContent() {
|
||||||
return StringEscapeUtils.unescapeHtml(content);
|
return StringUtil.sanitizeHtml(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SETTER & GETTER
|
// SETTER & GETTER
|
||||||
@ -126,7 +126,14 @@ public class ArticleVO extends PagingVO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setTitle(String title) {
|
public void setTitle(String title) {
|
||||||
this.title = title;
|
|
||||||
|
/*
|
||||||
|
* 통합자료관관리시스템과 동일하게 게시글 저장 처리를 수행하며,
|
||||||
|
* 제목의 경우, DB에 일부 특수문자에 대하여 치환되어 저장되고,
|
||||||
|
* 내용의 경우, HTML 요청된 그대로 저장하되 표출할 때 HTML Sanitizing하여 표출토록 처리하기로 협의됨에 따라
|
||||||
|
* 제목 설정시 치환되어 저장토록 함 (2021.12.21, 이규모차장님)
|
||||||
|
*/
|
||||||
|
this.title = StringUtil.getRemovedQuotesStr(title);
|
||||||
}
|
}
|
||||||
public String getContent() {
|
public String getContent() {
|
||||||
return content;
|
return content;
|
||||||
@ -287,6 +294,10 @@ public class ArticleVO extends PagingVO {
|
|||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSanitizedAnswer() {
|
||||||
|
return StringUtil.sanitizeHtml(answer);
|
||||||
|
}
|
||||||
|
|
||||||
public void setAnswer(String answer) {
|
public void setAnswer(String answer) {
|
||||||
this.answer = answer;
|
this.answer = answer;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,6 +137,12 @@ public class FaqController extends NlibCommonController {
|
|||||||
// 읽음처리 및 상세내용 조회
|
// 읽음처리 및 상세내용 조회
|
||||||
ArticleVO articleVO = faqService.selectArticle(searchArticleVO);
|
ArticleVO articleVO = faqService.selectArticle(searchArticleVO);
|
||||||
|
|
||||||
|
// AJAX OUT에 XSS처리되지 않은 HTML 전송 차단위한 변경 처리
|
||||||
|
if(articleVO != null) {
|
||||||
|
articleVO.setAnswer(articleVO.getSanitizedAnswer());
|
||||||
|
articleVO.setContent(articleVO.getSanitizedContent());
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------
|
//-------------------------------
|
||||||
// JSON변환 응답 처리
|
// JSON변환 응답 처리
|
||||||
//-------------------------------
|
//-------------------------------
|
||||||
|
|||||||
@ -273,6 +273,45 @@ public class StringUtil extends StringUtils {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 게시글 제목 등 허용되지 말아야하는 일부 특수문자에 대한 치환 처리하여 리턴
|
||||||
|
*
|
||||||
|
* @param val
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getRemovedQuotesStr(String val) {
|
||||||
|
|
||||||
|
if (isEmpty(val)) return val;
|
||||||
|
|
||||||
|
StringBuffer strBuff = new StringBuffer();
|
||||||
|
for (int j = 0; j < val.length(); j++) {
|
||||||
|
char c = val.charAt(j);
|
||||||
|
switch (c) {
|
||||||
|
case '<':
|
||||||
|
strBuff.append("<");
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
strBuff.append(">");
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
strBuff.append("&");
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
strBuff.append(""");
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
strBuff.append("'");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strBuff.append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strBuff.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 날짜 문자열(YYYYMMDD)을 받아서 화면 출력용 날짜 형식 문자열(YYYY-MM-DD)로 리턴한다.
|
* 날짜 문자열(YYYYMMDD)을 받아서 화면 출력용 날짜 형식 문자열(YYYY-MM-DD)로 리턴한다.
|
||||||
*
|
*
|
||||||
@ -391,7 +430,9 @@ public class StringUtil extends StringUtils {
|
|||||||
* @param html
|
* @param html
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static String sanitizeHtml(String html) {
|
public static String sanitizeHtml(String html) {
|
||||||
|
|
||||||
|
if(isEmpty(html)) return html;
|
||||||
|
|
||||||
PolicyFactory policy = new HtmlPolicyBuilder()
|
PolicyFactory policy = new HtmlPolicyBuilder()
|
||||||
.allowAttributes("src", "align", "title").onElements("img")
|
.allowAttributes("src", "align", "title").onElements("img")
|
||||||
|
|||||||
@ -342,7 +342,7 @@ function fn_downloadFile(attachFileId, fileSn) {
|
|||||||
<li class="wt-question">
|
<li class="wt-question">
|
||||||
<div class="w-tit">내용 <span class="required">*</span></div>
|
<div class="w-tit">내용 <span class="required">*</span></div>
|
||||||
<div class="w-form">
|
<div class="w-form">
|
||||||
<textarea name="content" id="content" cols="80" rows="10" placeholder="질문하실 내용을 입력하세요." style="width:100%;min-width:260px;"><c:out value='${searchArticle.unescapedContent}' escapeXml='false' /></textarea>
|
<textarea name="content" id="content" cols="80" rows="10" placeholder="질문하실 내용을 입력하세요." style="width:100%;min-width:260px;"><c:out value='${searchArticle.sanitizedContent}' escapeXml='false' /></textarea>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -121,7 +121,7 @@ function fn_downloadFile(attachFileId, fileSn) {
|
|||||||
<div class="view-body">
|
<div class="view-body">
|
||||||
<div class="view-con">
|
<div class="view-con">
|
||||||
<div class="view-txt">
|
<div class="view-txt">
|
||||||
<c:out value='${article.content}' escapeXml='false' />
|
<c:out value='${article.sanitizedContent}' escapeXml='false' />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul class="attachments">
|
<ul class="attachments">
|
||||||
|
|||||||
@ -145,7 +145,7 @@ function fn_downloadFile(attachFileId, fileSn) {
|
|||||||
<div class="view-con">
|
<div class="view-con">
|
||||||
<div class="view-txt">
|
<div class="view-txt">
|
||||||
<p>
|
<p>
|
||||||
<c:out value='${article.unescapedContent}' escapeXml="false" />
|
<c:out value='${article.sanitizedContent}' escapeXml='false' />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -156,7 +156,7 @@ function fn_downloadFile(attachFileId, fileSn) {
|
|||||||
<span class="right"><c:out value='${article.modDd }'/></span>
|
<span class="right"><c:out value='${article.modDd }'/></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="answer-con">
|
<div class="answer-con">
|
||||||
<p><c:out value='${article.answer}' escapeXml = 'false' /></p>
|
<p><c:out value='${article.sanitizedAnswer}' escapeXml = 'false' /></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</c:if>
|
</c:if>
|
||||||
|
|||||||
@ -62,6 +62,9 @@ $( document ).ready(function() {
|
|||||||
|
|
||||||
var $qObj = $(qObj);
|
var $qObj = $(qObj);
|
||||||
if($qObj.hasClass('on')) {
|
if($qObj.hasClass('on')) {
|
||||||
|
$qObj.removeClass("on");
|
||||||
|
$qObj.next(".answer").stop().slideUp(300);
|
||||||
|
$qObj.next(".answer").html("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,8 @@
|
|||||||
<url-pattern>*.do</url-pattern>
|
<url-pattern>*.do</url-pattern>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
|
<!-- 별도 OWASP HTML Sanitizer 사용으로 대체 -->
|
||||||
|
<!--
|
||||||
<filter>
|
<filter>
|
||||||
<filter-name>HTMLTagFilter</filter-name>
|
<filter-name>HTMLTagFilter</filter-name>
|
||||||
<filter-class>egovframework.rte.ptl.mvc.filter.HTMLTagFilter</filter-class>
|
<filter-class>egovframework.rte.ptl.mvc.filter.HTMLTagFilter</filter-class>
|
||||||
@ -28,6 +30,7 @@
|
|||||||
<filter-name>HTMLTagFilter</filter-name>
|
<filter-name>HTMLTagFilter</filter-name>
|
||||||
<url-pattern>*.do</url-pattern>
|
<url-pattern>*.do</url-pattern>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
-->
|
||||||
|
|
||||||
<!-- Spring Security Filter : DIGITALSHIP 2021.07.02 -->
|
<!-- Spring Security Filter : DIGITALSHIP 2021.07.02 -->
|
||||||
<filter>
|
<filter>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user