Spring Security
Spring Security
- Spring MVC 기반 애플리케이션 인증(Authentication)과 인가(Authorization) 기능 지원하는 보안 프레임워크
- Spring MVC 기반 애플리케이션 보안 적용에서의 표준과도 같음
- Spring 지원 Interceptor, Servlet Filter를 통해 보안 기능 구현도 가능하지만 보안 대부분의 기능을 Spring Security에서 안정적으로 지원하기 때문에 Spring Security 이용을 권장함
- Spring MVC 기반 애플리케이션 인증(Authentication)과 인가(Authorization) 기능 지원하는 보안 프레임워크
Spring Security 보안 강화 기능
- 다양한 유형의 사용자 인증 기능 적용
- form-login, 토큰 기반 적용, OAuth2 기반 인증, LDAP 인증 등
- 애플리케이션 사용자의 Role에 따른 권한 레벨 적용
- 애플리케이션 제공 리소스에 대한 접근 제어
- 민감 정보에 대한 데이터 암호화
- password 등
- SSL 적용
- 일반적으로 알려진 웹 보안 공격 차단
- SSO
- 클라이언트 인증서 기반 인증
- 메서드 보안
- 접근 제어 목록 (Access Control List) 보안
- 다양한 유형의 사용자 인증 기능 적용
Spring Security 사용 용어
Principal : 주체
- 애플리케이션에서 작업을 수행하는 사용자(디바이스 또는 시스템 등)
- 인증 프로세스가 성공적으로 수행된 사용자의 계정 정보를 의미
Authentication : 인증
- 애플리케이션 사용 시 사용자가 본인인지 확인하는 절차
- 신원을 증명하는 과정
- 정상 수행을 위해 Credential 필요
- Credential : 신원 증명 정보
Authorization : 인가, 권한 부여
- Authentication(인증)이 정상적으로 수행 된 사용자에게 하나 이상의 권한(Authority)를 부여
- 특정 애플리케이션의 특정 리소스에 접근 가능하도록 허가하는 과정
Access Control : 접근 제어
- 사용자가 애플리케이션의 리소스에 접근하는 행위를 제어하는 행위
Spring Security 특징
Spring Security 사용 이유
보안 강화 위한 솔루션으로 Spring Security만한 프레임워크가 없다
- 🔗Apache Shiro, 🔗OACC 등의 Java 애플리케이션을 위한 보안 프레임워크 존재
- Spring Security는 위 보안 프레임워크를 능가하는 기능 지원
- Spring과 궁합이 잘 맞음
기본 옵션만으로 불가한 특정 보안 요구 사항을 만족시키기 위한 코드 커스터마이징 용이 및 유연한 확장 가능
Spring Security 🔗SSR 방식에서의 구성
InMemory 방식 : 테스트환경 혹은 데모환경에서 사용
- Spring Security의 기본구조와 기본 동작방식 이해에 가장 좋은 Form-Login 방식
- Spring Security를 이용한 보안 설정
- HttpSecurity를 매개변수로 갖고 SecurityFilterChain을 리턴하는 Bean 생성
- HttpSecurity를 통해 Spring Security 지원 보안 설정 구성 가능
- 로컬환경에서의 테스트를 위해서는 CSRF설정 비활성 필요
- 🔗AntPattern
- 이름 충돌 방지 위한 XML NameSpace
DB 연동 방식 : Custom UserDetailsService를 사용하는 방법
- JavaConfiguration의 Bean 등록 변경
1 2 3 4 5 6 7
@Configuration public class JavaConfiguration { // 데이터를 DB에 저장, 패스위드 암호화 위한 Memberrepository, PasswordEncoder DI @Bean public MemberService dbMemberService(MemberRepository memberRepository, PasswordEncoder passwordEncoder) { return new DBMemberService(memberRepository, passwordEncoder);
- DBMemberService 구현
- Spring Security 제공 🔗PasswordEncoder
- 패스워드 같은 민감한(sensitive) 정보는 반드시 암호화 저장
- 패스워드는 암호화 된 상태에서 복호화 할 이유없음
- 즉, 🔗단방향 암호화 방식으로 암호화 ```java @Transactional public class DBMemberService implements MemberService { // MemberRepository, PasswordEncoder Bean 객체 DI private final MemberRepository memberRepository; private final PasswordEncoder passwordEncoder;
public DBMemberService(MemberRepository memberRepository, PasswordEncoder passwordEncoder) { this.memberRepository = memberRepository; this.passwordEncoder = passwordEncoder; }
public Member createMember(Member member) { verifyExistsEmail(member.getEmail());
1 2 3 4 5 6 7 8 9 10
// PasswordEncoder 사용하여 패스워드 암호화 String encryptedPassword = passwordEncoder.encode(member.getPassword()); // 암호화된 패스워드를 password 필드에 할당 member.setPassword(encryptedPassword); Member savedMember = memberRepository.save(member); System.out.println("# Create Member in DB"); return savedMember; }
… … } ```
- Custom UserDetailsService 구현
- Spring Security 제공 컴포넌트 중 하나인 UserDetailsService
- UserDetailsService는 User 정보를 로드하는 핵심 인터페이스
- UserDetailsManager : UserDetailsService를 상속하는 확장 인터페이스
- InMemberUserDetailsManager : UserDetailsManager 의 구현체
- UserDetails는 UserDetailsService에 의해 로드되어 인증을 위해 사용되는 핵심 User 정보 표현 인터페이스
- 직접사용되지는 않고 Authentication 객체로 캡슐화되어 제공됨 ```java // DB의 인증정보로 인증 처리하는 Custom UserDetailsService @Component public class HelloUserDetailsService implements UserDetailsService { private final MemberRepository memberRepository; private final HelloAuthorityUtils authorityUtils;
public HelloUserDetailsServiceV(MemberRepository memberRepository, HelloAuthorityUtils authorityUtils) { this.memberRepository = memberRepository; this.authorityUtils = authorityUtils; }
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { Optional
optionalMember = memberRepository.findByEmail(username); Member findMember = optionalMember.orElseThrow(() -> new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND)); 1
return new HelloUserDetails(findMember)l }
// DB 조회 회원 정보를 Spring Security의 User 정보로 변환하는 과정, User 권한정보 생성 과정 캡슐화 private final class HelloUserDetails extends Member implememts UserDetails { HelloUserDetails(Member member) { setMemberId(member.getMemberId()); setName(member.getName()); setEmail(member.getEmail()); setPassword(member.getPassword()); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
@Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorityUtils.createAuthorities(this.getEmail()); } @Override public String getUsername() { return getEmail(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } } }
- Spring Security 제공 컴포넌트 중 하나인 UserDetailsService
// User 권한 매핑, 생성하는 HelloAuthorityUtils @Component public class HelloAuthorityUtils { // .yml 추가 프로퍼티 가져오는 표현식 // @Value(“${프로퍼티_경로}”) // 사용 전 .yml파일에 관리자 이메일 주소 정의 필요 @Value(“${mail.address.admin}”) private String adminMailAddress;
// AuthorityUtils 클래스 사용하여 관리자용 권한 목록 생성 private final List
ADMIN_ROLES = AuthorityUtils.createAuthorityList("ROLE_ADMIN", "ROLE_USER"); // AuthorityUtils 클래스 사용하여 일반 사용 권한 목록 생성 private final List
USER_ROLES = AuthorityUtils.createAuthorityList("ROLE_USER"); public List
createAuthorities(String email) { // 매개변수 email과 .yml파일의 이메일과 동일하다면 관리자용 권한 리턴 if (email.equals(adminMailAddress)) { return ADMIN_ROLES; } return USER_ROLES; } } ``` - User Role 을 DB에서 관리
- JPA 통한 User와 User 권한정보간의 연관관계 매핑 추가
- 회원가입 시, User의 권한 정보를 DB에 저장 추가
- 로그인 인증 시, User 권한정보를 DB 조회 작업 추가
- JavaConfiguration의 Bean 등록 변경
- 🔗bcrypt 알고리즘
- 🔗Clickjacking 공격