← home

워드프레스 – 앵글브라켓(<, >)에 둘러싸인 일반 텍스트 보호

워드프레스에서 댓글을 작성하다보면 앵글브라켓(<, >)에 둘러싸인 텍스트가 사라지는 경우가 있습니다. ‘경우’라고 말하는 분명한 이유가 있는데요, HTML 요소인 경우 사용자 권한에 따라 부분적으로 나타나기도 하고 사라지기도 하며, HTML 요소가 아닌 일반 텍스트의 경우 아예 사라지기 때문입니다. 개발자나 코더들은 그 이유를 잘 알고 있겠지만, 일반 사용자에게 이것은 그저 오류일 뿐입니다.

이러한 문제를 보완하기 위해서는 그 원인을 잘 알아야 하겠습니다.
워드프레스는 댓글 작성자, 내용 등 사용자에 의해 입력된 내용을 DB에 저장하기 전에 필터링을 합니다. 그 기본 필터 중 하나가 KSES 필터입니다. 이것은 악의적인 코드 삽입을 방지하기 위해 허락된 HTML요소만 유지하고 나머지는 제거하는 기능을 합니다. 보안을 위해서 매우 중요한 필터라고 말할 수 있습니다.
하지만 우리는 글을 쓸 때, 책이나 영화 제목 등을 간편하게 표기할 때 앵글브라켓을 자주 사용하잖아요? 앵글브라켓에 둘러싸인 내용이 문맥상 없어서는 안되는 경우가 많기 때문에, 이 부분을 반드시 보완해주어야 할 것입니다. &lt;와 &gt;를 사용하라고 구질구질하게 설명하지 않으려면 제가 사용하는 방법을 도입해보는 것은 어떠실지요^^

어느 시점에서 무엇을 해야하는지만 알고 있다면 방법은 간단합니다.
우선, 댓글이 DB에 저장되기 전에 어떤 훅에 의하여 필터링 되는지를 찾아보세요.
DB 저장 직전에 ‘pre_comment_content’ 라는 필터 훅이 걸려있군요.
그렇다면 ‘pre_comment_content’ 라는 필터 훅에 걸려있는 필터들을 찾아보세요.
그러면 KSES 필터가 기본 우선순위(10)로 걸려있는 것을 확인 할 수 있을 것입니다. 저는 이 필터가 실행되기 전에 앵글브라켓에 둘러싸인 텍스트가 HTML 태그인지 아닌지를 확인하여, HTML 태그가 아닌 경우 앵글브라켓을 HTML엔터티로 미리 바꿔주려 합니다.

functions.php 파일 등에 아래 코드를 추가해주세요.

add_filter( 'pre_comment_content', 'my_preserve_anglebracket_text', 1 );
add_filter( 'comment_text', 'my_preserve_anglebracket_string', 1 );

function my_preserve_anglebracket_text($r){
	return preg_replace_callback( '%(&lt;!--.*?(--&gt;|$))|(&lt;[^&gt;]*(&gt;|$)|&gt;)%', 'my_preserve_anglebracket_text_callback', $r );
}

function my_preserve_anglebracket_text_callback($match){
	return my_preserve_anglebracket_text_split($match[0]);
}

function my_preserve_anglebracket_text_split($string){
	$html_tags = explode('|', 'a|abbr|address|area|article|aside|audio|b|base|bdi|bdo|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|menu|meta|meter|nav|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|u|ul|var|video|wbr');
	
	preg_match('%^&lt;\s*(/\s*)?([a-zA-Z0-9]+)([^&gt;]*)&gt;?$%', $string, $matches);
	
	$tag = isset($matches[2]) ? strtolower($matches[2]) : '';
	if( ! $tag || ! in_array($tag, $html_tags) )
		$string = htmlspecialchars($string);
	return $string;
}

라인 1: DB에 저장시, KSES 필터 등이 실행되기 전에 실행되도록 훅을 겁니다.
라인 2: 기존 DB에 필터링되지 않은 코드가 있을 수 있으므로, 출력시에도 훅을 겁니다.
라인 4~6: 앵글브라켓으로 둘러싸인 문자열인지 검사합니다.
라인 8~22: 앵글브라켓으로 둘러싸인 문자열인 경우, HTML태그인지 아닌지 검사하여, 아닌경우 HTML 엔터티로 변환해줍니다.

이렇게하면 KSES 필터에서 HTML 엔터티 부분은 검사하지 않을 것이므로 앵글브라켓으로 둘러싸인 부분은 문자열로서 온전히 DB에 저장될 것이고, 이 플러그인을 사용하기 전에 ‘unfiltered_html’ 권한을 가진 사용자에 의해 이미 DB에 저장된앵글브라켓 역시 올바르게 출력될 것입니다.

← home