Technote

보안 실무

연재 REST API 와 헤드리스 8부 중 6부

사용자 열거 막기 — REST 가 기본으로 흘리는 것

/wp-json/wp/v2/users 는 로그인하지 않아도 열립니다. 거기 실린 slug 는 대개 로그인 아이디이고, 그러면 공격자는 비밀번호 하나만 남겨 두게 됩니다.

워드프레스는 글을 발행한 사용자의 목록을 기본으로 공개합니다. 로그인하지 않은 채 /wp-json/wp/v2/users 를 열면 이름과 slug 가 나옵니다. 그리고 그 slug 는 기본 설정에서 로그인 아이디와 같습니다.

아이디가 알려지면 무엇이 달라지나

정확하게 말하는 것이 중요합니다. 사용자 열거는 그 자체로 취약점이 아닙니다. 공격자의 비용을 낮추는 일입니다. 로그인은 아이디와 비밀번호 두 개를 맞혀야 하는 문제인데, 아이디가 공개되면 비밀번호 하나짜리 문제로 줄어듭니다. 여기에 로그인 시도 제한이 없으면 자동화된 대입이 성립합니다.

흘러나가는 경로는 하나가 아닙니다.

아이디가 새는 경로 — 한 곳만 막으면 나머지가 남는다

닫는 방법 — 두 겹으로

첫 겹은 아이디와 표시 이름을 분리하는 것입니다. 이것이 가장 근본적입니다. 어떤 경로로 이름이 새더라도 그것이 로그인 아이디가 아니면 위의 계산이 성립하지 않습니다.

# slug(=user_nicename) 을 로그인 아이디와 다르게 바꾼다
wp user update 1 --user_nicename=team --display_name="WPER 팀"

둘째 겹은 경로를 닫는 것입니다. 로그아웃 상태에서는 사용자 컬렉션 자체를 없애고, 작성자 아카이브 탐색을 끊습니다. 로그인 상태는 건드리지 않아야 블록 에디터의 작성자 선택이 계속 동작합니다.

// 로그아웃 상태에서만 사용자 라우트를 걷어낸다.
add_filter( 'rest_endpoints', function ( $endpoints ) {
	if ( is_user_logged_in() ) {
		return $endpoints;
	}

	unset( $endpoints['/wp/v2/users'] );
	unset( $endpoints['/wp/v2/users/(?P<id>[d]+)'] );

	return $endpoints;
} );

// 작성자 아카이브를 쓰지 않는 사이트라면 탐색 자체를 끊는다.
add_action( 'template_redirect', function () {
	if ( is_author() || isset( $_GET['author'] ) ) {
		wp_safe_redirect( home_url( '/' ), 301 );
		exit;
	}
} );

두 번째 조각은 작성자 아카이브를 쓰지 않는 사이트에서만 맞습니다. 여러 필자가 있고 작성자 페이지가 콘텐츠 자산인 사이트라면 이 코드는 자산을 지우는 코드가 됩니다. 보안 설정을 복사해 붙이기 전에 그 사이트에서 그 기능이 쓰이는지 먼저 봅니다.

서버 계층에서도 한 겹

애플리케이션에서 막았다면 서버에서도 같은 규칙을 둡니다. nginx 에서 비인증 /wp-json/wp/v2/users 요청과 ?author= 질의를 끊어 두면, 플러그인이 필터를 덮어쓰거나 테마가 바뀌어도 한 겹이 남습니다. 같은 방어를 두 계층에 두는 이유는 중복이 아니라, 한 겹이 빠져도 뚫리지 않게 하기 위해서입니다.

막았는지 확인하는 것도 잊지 마세요. 로그아웃 상태의 브라우저나 curl 로 실제로 두드려 보고, 열려 있는 경로가 남았는지 봅니다. 우리가 만든 무료 진단 도구는 이 항목을 점검 목록에 포함하고 있어서, 사이트를 옮기거나 플러그인을 바꾼 뒤에 다시 열렸는지도 잡아냅니다.

로그인 보호와 하드닝 전반은 보안 아카이브에 정리돼 있습니다.

다음 회차

여기까지가 보안입니다. 다음 회차는 성능 — API 응답을 어느 계층에 캐시할 것인가, 그리고 캐시의 진짜 어려움인 무효화를 어떻게 설계하는가입니다.

이 주제의 다른 글

노하우 목록으로

보안 실무

리드 데이터는 자산이면서 책임입니다

연락처 목록은 마케팅 자산이지만 동시에 개인정보입니다. 필요한 만큼만 받고, 기간을 정해 두고, 그 기간이 지나면 실제로 지우는 세 가지가 핵심입니다.

마케터 3분 읽기

보안 실무

분석과 개인정보 — 최소 수집과 고지의 실제

배너를 띄우는 것과 동의를 받는 것은 다릅니다. 무엇을 왜 수집하는지 스스로 설명할 수 있어야 하고, 보관 기간은 방치가 아니라 결정이어야 합니다.

마케터 4분 읽기

보안 실무

웹훅 수신 — nonce 를 걸면 100% 실패합니다

외부 서버에는 쿠키도 nonce 도 없습니다. 검증은 서명이나 공유 키로 하고, hash_equals 로 비교하며, 서명은 반드시 원본 바디에 대고 계산합니다.

개발자 6분 읽기

₩270,000 · 신청하기