템플릿에서 값을 출력할 때 지켜야 하는 규칙은 하나입니다. 출력하는 그 자리에서, 그 자리에 맞는 함수로 감싼다. 워드프레스 코딩 표준에서 이스케이프 없는 echo 가 리뷰에서 반려되는 이유가 이것입니다.
왜 입력이 아니라 출력인가
“저장할 때 한 번 처리해 두면 되지 않나” 는 자연스러운 질문입니다. 답은 같은 값이 여러 자리로 나가기 때문입니다. 글 제목 하나만 해도 본문 텍스트로, title 속성 값으로, 검색 결과의 JSON 으로 나갑니다. 세 자리의 안전 규칙이 각각 다릅니다.
입력 시점에 이스케이프하면 그 순간 자리 하나를 골라 고정하는 셈이고, 나머지 자리는 전부 어긋납니다. 게다가 원본이 훼손되어 검색 · 정렬 · 내보내기가 함께 이상해집니다. 반대로 출력 시점에 처리하면 원본은 원본대로 남고, 자리마다 맞는 처리를 할 수 있습니다.
실무적인 이점도 큽니다. 이스케이프가 echo 와 같은 줄에 있으면 한 줄만 보고 안전 여부를 판정할 수 있습니다. 저장 로직까지 거슬러 올라가 확인해야 한다면 그것은 검토가 아니라 추적입니다.
자리별 함수
<a class="<?php echo esc_attr( $class ); ?>"
href="<?php echo esc_url( $url ); ?>">
<?php echo esc_html( $title ); ?>
</a>
<div class="entry">
<?php echo wp_kses_post( $rich_html ); ?>
</div>
esc_html() 과 esc_attr() 을 굳이 나누는 이유는 속성 안에서는 따옴표가 탈출 문자이기 때문입니다. 값에 따옴표가 섞이면 속성이 그 자리에서 끊기고 그 뒤가 새로운 속성으로 해석됩니다. 태그 밖에서는 문제가 되지 않는 문자가 태그 안에서는 문제가 되는 것입니다.
esc_url() 은 이스케이프에 더해 허용된 프로토콜인지도 봅니다. 사용자가 넣은 주소가 스크립트를 실행하는 형태일 수 있고, 그것을 esc_attr() 로는 걸러내지 못합니다. 링크 자리에는 반드시 esc_url() 을 씁니다.
wp_kses_post() 는 성격이 다릅니다. 이스케이프가 아니라 허용 목록에 따른 필터링이라, 문단 · 링크 · 강조 같은 태그는 살아남고 스크립트는 제거됩니다. 에디터로 작성된 본문처럼 마크업을 살려야 하는 값에만 씁니다.
흔한 오용 세 가지
첫 줄은 눈에 보여서 금방 발견됩니다. 문제는 두 번째와 세 번째입니다 — 화면이 멀쩡해 보이므로 리뷰를 통과합니다. “이스케이프 함수를 썼다” 는 사실만으로 안전이 보장되지는 않는다는 뜻입니다.
번역이 섞이면 esc_html__() · esc_attr_e() 처럼 합쳐진 함수를 씁니다. 번역문에도 같은 규칙이 적용되기 때문입니다 — 번역 파일은 우리가 통제하지 않는 경우가 있습니다.
마지막으로 esc_url() 과 esc_url_raw() 를 구분합니다. 화면에 출력할 때는 앞쪽을, DB 저장이나 리다이렉트처럼 기계가 소비할 때는 뒤쪽을 씁니다. 앞쪽은 HTML 용으로 & 를 엔티티로 바꾸기 때문에 그대로 저장하면 값이 달라집니다.
테마 · 플러그인 코드의 보안 관행은 보안 아카이브에서 더 다루고, 운영 중인 사이트의 취약점 진단은 최적화 지원 사업에 전/후 대조로 포함돼 있습니다.
다음 회차
출력이 안전해졌으니 이제 무엇을 출력할지 정할 차례입니다. 다음 회차는 템플릿 안에서 보조 쿼리를 쓰는 방법이고, 한 줄을 빠뜨렸을 때 생기는 아주 헷갈리는 증상을 함께 다룹니다.