[워드프레스] 19. 보안 : nonce·sanitize·escape 3종 방어 완전 정리

워드프레스 해부 19편 - nonce·sanitize·escape 3종 방어 완전 정리

작성자

카테고리:

* 이 게시물은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

(워드프레스 해부 ⑲) 보안

워드프레스를 확장하다 보면 폼을 만들고, 입력을 받고, 값을 출력한다. 이 세 지점이 각각 공격 표면이다. 그래서 방어도 세 가지 — nonce, sanitize, escape. 이 3종을 습관으로 만들면 대부분의 흔한 취약점을 막는다.

  • nonce — 요청 위조(CSRF) 방지. “이 폼 제출이 정말 우리 사이트에서, 이 사용자가 보낸 게 맞나”를 확인하는 일회성 토큰.
  • sanitize(정화) — 입력을 저장하기 전에 위험한 걸 걸러낸다. sanitize_text_field(), sanitize_email() 등.
  • escape(이스케이프) — 출력할 때 HTML/JS로 해석될 수 있는 문자를 무해하게. esc_html(), esc_attr(), esc_url().

외우기 쉽게: “들어올 땐 sanitize, 나갈 땐 escape, 폼엔 nonce.” 특히 escape는 “신뢰할 수 없는 데이터”뿐 아니라 출력하는 거의 모든 동적 값에 습관적으로 거는 게 안전하다.

직접 해보기

// 안전한 폼 처리의 전형
// 1) 폼에 nonce 필드 심기
wp_nonce_field( 'save_my_form', 'my_form_nonce' );

// 2) 제출 처리 — nonce 검증 → sanitize → 저장
if ( isset( $_POST['my_form_nonce'] )
     && wp_verify_nonce( $_POST['my_form_nonce'], 'save_my_form' ) ) {
    $name = sanitize_text_field( $_POST['name'] );   // 입력 정화
    update_option( 'my_name', $name );
}

// 3) 출력 — 언제나 escape
echo '<p>' . esc_html( get_option( 'my_name' ) ) . '</p>';

✅ 확인 — 폼을 만들 때 wp_nonce_field()를 넣고, 처리에서 wp_verify_nonce()로 검증하는 흐름을 갖추자. nonce 없이 저장 처리를 하면, 외부 사이트가 사용자 몰래 요청을 위조할 수 있는 구멍이 생긴다. 이 3종이 워드프레스 개발의 기본 위생이다.

코드로 보는 3종 세트

폼 하나의 생애로 보면 어디에 무엇을 쓰는지 명확해진다. 출력 시 nonce 심기 → 제출 시 nonce 검증 + sanitize → 화면 출력 시 escape.

// 폼 출력 — nonce 심기
wp_nonce_field( 'save_profile', 'profile_nonce' );

// 제출 처리 — 검증 후 정화
if ( ! isset( $_POST['profile_nonce'] ) ||
     ! wp_verify_nonce( $_POST['profile_nonce'], 'save_profile' ) ) wp_die( '요청 거부' );
$name = sanitize_text_field( $_POST['name'] ?? '' );   // 입력 정화
update_user_meta( $uid, 'display', $name );

// 화면 출력 — 이스케이프
echo '<span>' . esc_html( $name ) . '</span>';

sanitize vs escape — 헷갈리지 않기

핵심 구분 하나. sanitize는 ‘들어올 때'(입력·저장), escape는 ‘나갈 때'(출력)다. 둘은 대체가 아니라 짝이다. 저장 시 정화했더라도, 출력할 땐 다시 이스케이프한다 — DB의 값이 어디서 왔든 믿지 않는 게 원칙이기 때문이다(신뢰 경계). ‘입력은 sanitize, 출력은 escape’를 주문처럼 외우자.

escape는 ‘넣는 자리’에 맞춰

이스케이프 함수는 값을 어디에 넣느냐로 고른다. 맥락을 틀리면(속성 자리에 esc_html) 여전히 뚫린다.

넣는 자리함수
HTML 본문esc_html()
태그 속성값esc_attr()
URLesc_url()
인라인 JSesc_js()
번역문 + 출력esc_html__() / esc_html_e()

권한 검사도 잊지 말고

한 가지 더. nonce는 ‘위조 방지‘지 ‘권한‘이 아니다. nonce가 맞아도, 그 사용자가 그 작업을 할 자격이 있는지는 current_user_can(11편)으로 따로 확인해야 한다. nonce(진짜 우리 폼이 맞나) + capability(이 사람이 해도 되나) + sanitize/escape(값이 안전한가), 이 셋이 함께여야 방어가 완성된다.

이걸로 코어 엔진 모듈 끝. 훅으로 끼어들고, 쿼리로 뽑고, 템플릿으로 그리고, 자원을 싣고, 예약·캐시·보안까지 — 워드프레스가 “동작”하는 방식을 다 봤다. 다음 모듈은 이 엔진 위에 내 기능을 얹는 확장 — 커스텀 포스트 타입, 숏코드, REST API로 넘어간다.

자주 묻는 질문 (FAQ)

nonce·sanitize·escape는 각각 뭘 막나요?

nonce는 위조 요청(CSRF), sanitize는 잘못된 입력, escape는 출력 시 XSS를 막습니다. 입력은 sanitize, 출력은 escape가 원칙입니다.

escape는 언제 하나요?

값을 화면에 출력하는 바로 그 순간, 맥락에 맞는 함수(esc_html·esc_attr·esc_url)로 이스케이프합니다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다