
최근 몇 년 동안 보안성과 편의성을 모두 갖춘 새로운 인증 방식이 주목받고 있습니다.
바로 웹 인증 표준과 이를 기반으로 하는 패스키입니다.
이는 기존의 사용자 이름과 비밀번호를 대체하여, 피싱에 강력하고 사용이 훨씬 간편한 인증 경험을 제공합니다.
Spring Security 환경에서 어떻게 이 혁신적인 인증 방식을 도입할 수 있는지 설명합니다.
Web Authentication API 는 W3C와 FIDO Alliance가 협력하여 개발한 웹 표준입니다.
이는 웹 애플리케이션 및 서비스에서 공개 키 암호화를 사용하여 사용자를 인증하는 인터페이스를 표준화합니다.
Passkey는 WebAuthn 표준을 준수하는 FIDO 자격 증명을 일컫는 사용자 친화적인 용어입니다.
Passkeys는 사용자 장치에 저장되며, 사용자의 생체 인식이나 장치 PIN을 통해 활성화됩니다.
| 특징 | Passkeys (WebAuthn) | 기존 비밀번호 기반 인증 |
|---|---|---|
| 보안성 | 공개 키 암호화 사용, 피싱 및 중간자 공격에 강력 | 비밀번호 유출 위험, 피싱 공격에 취약 |
| 편의성 | 생체 인식 또는 PIN으로 자동 로그인 (입력 불필요) | 길고 복잡한 비밀번호를 기억하고 입력해야 함 |
| 이식성 | iCloud, Google 계정 등을 통해 여러 장치에 동기화 가능 | 각 서비스마다 비밀번호를 별도로 관리해야 함 |
| 인증 요소 | 사용자 장치 자체 (Authenticator) | 사용자가 기억하는 지식 (Knowledge) |
WebAuthn의 핵심은 사용자 인증에 필요한 개인 키가 외부로 전송되지 않고 장치 내부에 안전하게 보관된다는 점입니다.
Spring Security는 WebAuthn 지원을 통합하여 개발자가 비교적 적은 설정으로 패스키 인증을 도입할 수 있도록 돕고 있습니다.
WebAuthn 지원이 포함된 Spring Security 모듈을 프로젝트에 추가합니다.
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-webauthn</artifactId>
<version>0.0.1-SNAPSHOT</version> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
기존 SecurityFilterChain 설정에 WebAuthn 지원을 추가합니다.
WebAuthn은 초기 등록을 위해 폼 기반 로그인(Form Login)과 함께 사용될 수 있습니다.
Java Config 예제:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
@Configuration
public class SecurityConfiguration {
// 1. PasswordEncoder 설정
@Bean
public PasswordEncoder passwordEncoder() {
// 실제 애플리케이션에서는 안전한 인코더를 사용해야 합니다.
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
// 2. 초기 사용자 설정 (WebAuthn 등록을 위한 폼 로그인 계정)
@Bean
public UserDetailsService userDetailsService() {
// 실제 애플리케이션에서는 DB 기반의 UserDetailsService를 사용합니다.
return new InMemoryUserDetailsManager(
User.withUsername("josh")
.password(passwordEncoder().encode("pw")) // 실제로는 더 강력한 패스워드를 사용해야 합니다.
.roles("USER")
.build()
);
}
// 3. SecurityFilterChain 설정
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
// 로그인 페이지는 모두 접근 허용
.requestMatchers("/login", "/register-passkey").permitAll()
// 그 외 모든 요청은 인증 필요
.anyRequest().authenticated()
)
// 폼 로그인 설정 (최초 Passkey 등록을 위해 필요)
.formLogin(form -> form
.loginPage("/login")
)
// WebAuthn/Passkeys 지원 설정
.with(new WebAuthnConfigurer(), webauthn -> {
// Relying Party (RP) 정보 설정
webauthn.relyingPartyId("localhost") // 현재 도메인
.relyingPartyName("Beautiful Passkeys App")
.allowedOrigins("http://localhost:8080"); // 허용 오리진
// 사용자 등록 정보 저장소 및 기타 세부 설정 (실제 구현 시 필요)
// webauthn.credentialRepository(myCredentialRepository());
});
return http.build();
}
}
WebAuthn을 도입하면 사용자의 인증 플로우는 다음과 같이 단순화됩니다.
/register-passkey 엔드포인트WebAuthn은 보안이라는 비기능적 요구사항을 "우아하고, 효율적이며, 빠르게" 해결할 수 있게 합니다. 복잡한 비밀번호 관리, MFA(Multi-Factor Authentication) 구현 부담을 줄이면서도 훨씬 높은 수준의 보안을 달성합니다.
Passkeys는 Google, Apple, Microsoft 등 주요 IT 기업들이 적극적으로 지원하고 있는 만큼, 가까운 미래에 가장 보편적인 웹 인증 방식으로 자리 잡을 것입니다.
Spring Security의 WebAuthn 통합은 이러한 혁신적인 흐름에 발맞춰 안전하고 미래 지향적인 애플리케이션을 구축할 수 있게 해줍니다.
이번 WebAuthn 기반의 인증 도입 과정을 보면서, 개발 생태계가 오랜 숙제였던 보안과 사용자 경험의 상충 관계를 드디어 해소하는 단계에 접어들었다는 깊은 인상을 받았습니다.
개인적으로 가장 고무적인 부분은, 보안 강화가 더 이상 개발 복잡도 증가나 사용자의 불편함을 의미하지 않게 되었다는 점입니다.
지난 수년간 우리는 폼 기반 로그인, HTTP Basic, OAuth/OIDC, 그리고 고통스러운 MFA설정 등 수많은 인증 방식을 경험해 왔습니다.
이 과정에서 개발팀은 복잡한 비밀번호 정책 관리, 해시 및 솔트 처리, 저장소 보안 유지 등 비기능적 요구사항에 막대한 리소스를 투입해야 했고, 사용자들은 끝없이 새로운 비밀번호를 외우거나 분실하는 고충을 겪었습니다.
그러나 WebAuthn은 공개 키 암호화라는 근본적인 기술을 활용하여 이러한 문제를 한 번에 해결합니다.
피싱 공격에 취약한 기존 방식과 달리, 인증 요소가 장치 내부에 안전하게 격리되어 있어 서버나 네트워크 보안 문제를 회피합니다.
더욱이, Spring Security와 같은 프레임워크가 이 복잡한 표준을 간결한 설정 몇 줄로 추상화하여 제공하기 시작했다는 것은, '개발자의 고통을 줄이고 본업에 집중하게 만드는' 스프링 진영의 철학이 이번에도 빛을 발한 결과라고 느껴집니다.
결국, 이번 통합은 기술적으로 매우 우수할 뿐만 아니라, 엔터프라이즈 환경에 적용될 때 개발 효율성과 최종 사용자 만족도를 동시에 끌어올릴 수 있는 근본적인 발전이라는 점에서 매우 긍정적이고 기대가 큽니다.
이는 복잡하고 지루하게 느껴졌던 보안 영역이 이제는 우아하고 필수적인 기본 기능으로 자리매김하고 있음을 보여줍니다.