정수원님의 강의 스프링 시큐리티 완전 정복 [6.x 개정판] 보면서 공부한 내용입니다.
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize ->
// 요청 객체에 대하여 권한을 모델링 하겠다라는 의미
authorize.anyRequest().authenticated());
// 어떤 요청에도 인증이 되어야한다는 권한 설정
// 즉, 애플리케이션의 모든 엔드포인트가 최소한 인증된 보안 컨텍스트가 있어야 한다고 알리는 것
return http.build();
}
- requestMatchers(String... urlPatterns)
- 보호가 필요한 자원 경로를 한 개 이상 정의
- requestMatchers(RequestMatcher... requestMatchers)
- 보호가 필요한 자원 경로를 한 개 이상 정의
- AntPathRequestMatcher, MvcRequestMatcher 등의 구현체를 사용 가능
- requestMatchers(HttpMethod method, String... utlPatterns)
- Http Method 와 보호가 필요한 자원 경로를 한 개 이상 정의
→ requestMatchers() 안에 들어가는 내용은 "서버가 보호해야되는 자원으로 임의대로 접근할 수 없고 접근하기 위해서는 특정 권한 규칙을 따라야한다"라고 하는 url 또는 패턴들을 설정]
requestMatchers("/admin").hasRole("ADMIN")
💡 주의사항
- 클라이언트 요청에 대하여 위에서 부터 아래로 나열된 순서대로 처리하며 요청에 대하여 첫 번째 일치만 적용되고 다음 순서로 넘어가지 않는다
- 즉, /admin/가 /admin/db 요청을 포함하므로 /admin/를 먼저 정의하면 /admin/db의 권한 규칙이 적용되지 않을 수 있다.
- 그러므로 엔드 포인트 설정 시 좁은 범위(/admin/db)의 권한 규칙을 먼저 설정한 후 큰 번위(/admin/**)를 설정해야 한다
ROLE에 따른 접근
ROLE : user
접근 허용인 페이지ROLE : user
접근 불가능 페이지http.securityMatcher("/api/**").authorizeHttpRequests(auth -> auth.requestMatchers(…))
- securityMatcher(String... urlPatterns)
- 특정 자원 보호가 필요한 경로를 정의한다
- securityMatcher(RequestMatcher... requestMatchers)
- 특정 자원 보호가 필요한 경로를 정의한다. AntPathRequestMatcher, MvcRequestMatcher 등의 구현체를 사용할 수 있다
WebExpressionAuthorizationManager
를 제공requestMatchers().access(new WebExpressionAuthorizationManager("expression"))
requestMatchers("/admin/db").access(anyOf(hasAuthority("db"), hasRole("ADMIN")))
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
public void adminOnlyMethod() {
// 관리자 역할을 가진 사용자만 실행할 수 있는 메소드
}
@PostAuthorize("returnObject.owner == authentication.name")
public BankAccount getAccount(Long id) {
// returnObject : return하는 객체 (BankAccount)
// returnObject.owner : return하는 객체안에 있는 속성
// => 계정를 반환하지만 계정의 소유자만 결과를 볼 수 있음
return new BankAccount();
}
@PreFilter("filterObject.owner == authentication.name")
public Collection<BankAccount> updateAccounts(BankAccount[] data){
return data;
// BankAccount에 저장되어 있는 여러개의 객체들을 PreFilter 조건에 따라 필터링해서 반환해줌
// BankAccount에 a,b,c 객체가 있는데 필터링된 것이 b에만 맞는다면 b만 return된다
}
💡 PreFilter와 반대
- PreFilter는 미리 필터링해서 그 결과를 가지고 메서드 안으로 진입해서 처리한다면, PostFilter는 어떤 결과가 주어지지 않지만 메서드에 진입한 뒤 결과들을 가지고 와서 다시 반환할 때 특정 조건에 만족하는 객체만 반환한다
@PostFilter("filterObject.owner == authentication.name")
public List<BankAccount> readAccounts1(){ // 특정 조건을 받지 않는다
return dataService.readList();
// PostFilter 필터에 만족하는 객체만 반환
}
@Secured("ROLE_USER")
public void performUserOperation() {
// ROLE_USER 권한을 가진 사용자만 이 메소드를 실행할 수 있다.
}
- @RolesAllowed
- 권한을 가진 사용자만 접근 가능
- ex) @RolesAllowed("USER")
- @PermitAll
- 모든 사용가 접근 가능
- @DenyAll
- 모든 사용자 접근 불가능
// IsAdmin이라는 어노테이션 설정
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasRole('ADMIN')")
public @interface IsAdmin {}
// @PreAuthorize("hasRole('ADMIN')")를 다음과 같이 @IsAdmin으로 간소화할 수 있다
@IsAdmin
public BankAccount readAccount(Long id) {
// ADMIN 권한을 가진 사용자에게 메소드 호출이 승인 될 수 있다
}
@Controller
@PreAuthorize("hasAuthority('ROLE_USER')") // 전체적으로는 실행되지만 클래스에 설정된 어노테이션이 있으면 클래스 어노테이션이 우선적으로 실행된다
public class MyController {
@GetMapping("/endpoint")
@PreAuthorize("hasAuthority('ROLE_ADMIN')") // 이 설정이 우선적으로 동작한다
public String endpoint() { ... }
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (webSecurity) -> {
webSecurity.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations());
// 정적 자원들에 대해 보안 필터를 거치지 않도록 설정 가능
};
}
💡 StaticResourceLocation 클래스 안에 있는 정적 자원 경로
- CSS("/css/**"),
- JAVA_SCRIPT("/js/**"),
- IMAGES("/images/**"),
- WEB_JARS("/webjars/**"),
- FAVICON("/favicon.", "//icon-*");
💡 XSS란?
- Cross Site Script의 약자로 웹사이트에 악성코드를 주입하는 행동을 말하며, 공격자가 웹사이트를 넘어서 공격한다는 뜻에서 유래되었다. 공격자는 웹사이트 입력 또는 출력 부분에 스크립트를 심어 웹사이트 뿐만 아니라 다른 사용자, 심지어 서버도 공격 가능하다는 특징이 있다. XSS는 대표적으로 Reflected XSS, Stored XSS, Dom based XSS 세 가지 유형으로 나뉜다.
<propertyname="hierarchy">
<value>
ROLE_A>ROLE_B
ROLE_B>ROLE_C
ROLE_C>ROLE_D
// ROLE_A 를 가진 모든 사용자는 ROLE_B, ROLE_C 및 ROLE_D 도 가지게 된다
// ROLE_B는 ROLE_C, ROLE_D 권한을 가지게 된다
</value>
</property>