Tag Archives: Security

Spring Security 정리

SecurityFilter와 ServletFilter

이름은 똑같이 Filter이지만 Servlet에서 관리되는 Filter와 구조가 다르다.

여기서는 ServletFilter와 SecurityFilter로 구분하겠다.

 

https://docs.spring.io/spring-security/site/docs/3.0.x/reference/security-filter-chain.html

<filter>
  <filter-name>myFilter</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
  <filter-name>myFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

DelegateFilterProxy만 ServletFilter이다.

다른 SecurityFilter는 이 하위에서 동작한다.

 

ex) API와 웹화면이 별도의 체인 사용

<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
  <sec:filter-chain-map path-type="ant">
     <sec:filter-chain pattern="/webServices/**" filters="
           securityContextPersistenceFilterWithASCFalse,
           basicAuthenticationFilter,
           exceptionTranslationFilter,
           filterSecurityInterceptor" />
     <sec:filter-chain pattern="/**" filters="
           securityContextPersistenceFilterWithASCTrue,
           formLoginFilter,
           exceptionTranslationFilter,
           filterSecurityInterceptor" />
  </sec:filter-chain-map>
</bean>

SecurityFilter중 하나인 LogoutFilter의 선언부

public class LogoutFilter extends GenericFilterBean {
}

public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware,
		EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean {
}

SecurityFilter도 javax.servlet.Filter를 상속받지만 아예 다른 형태로 만드는게 혼란이 없지 않았을까 하는 생각이 든다.

 

Cors필터나 기타 인증필터를 추가해서 Security인증을 하고싶다면 ServetFilter가 아닌 SecurityFilterChain에 추가를 해야한다.

Security의 핵심인 FilterChain

https://stackoverflow.com/questions/41480102/how-spring-security-filter-chain-works

SpringSecurity JavaConfig 기본설정부분의 일부

@Configuration
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {
	override fun configure(http: HttpSecurity?) {
		http!!.csrf().disable()
				.cors().and()
				.authorizeRequests()
				.anyRequest().authenticated()
				.and()
	}
}

기본적으로 셋팅되는 필터들

서로간에 강한 의존성을 가지며 순서가 중요하다.

FilterChainProxy

1 WebAsyncManagerIntegrationFilter
2 SecurityContextPersistenceFilter
3 HeaderWriterFilter
4 CorsFilter --optional
5 LogoutFilter
6 UsernamePasswordAuthenticationFilter
7 RequestCacheAwareFilter
8 SecurityContextHolderAwareRequestFilter
9 AnonymousAuthenticationFilter
0 SessionManagementFilter
1 ExceptionTranslationFilter
2 FilterSecurityInterceptor

 

FilterChain을 구동시키는 Filter만

JWT나 CORS 필터 적용이 필요하다면 Security에 올리는게 좋다.

 

RoleVoter

 

 

Linux Chmod 스타일 권한 숫자 만들기.

JWT토큰 관련 설계를 만들다가

파라미터를 짧게 만들려고

웹사이트 화면이나 API에서 사용할 수 있는 권한의 종류는 생각보다 많지 않아서 미리 정의가능하다.

VIEW
READ
WRITE
MODIFY
DELETE
EXECUTE

 

좀 더 나올수도 있지만

Chmod Style

--- user ---
r 400
w 200
x 100
--- group ---
r 40
w 20
x 10
--- other ---
r 4
w 2
x 1

여기서 숫자 규칙은..

어떤숫자 조합을 더해도 중복숫자가 없어야한다.

이 규칙에 따라 위의 정의된 권한에 숫자를 부여해보면

VIEW 1
READ 2
WRITE 4
MODIFY 8
DELETE 16
EXECUTE 32

ex) WRITE = VIEW + READ + 1

이런 규칙으로 계산을 하면된다. 어차피 2씩 곱하는거나 마찬가지.

숫자를 더 줄일 규칙이 있는지 찾아봐야겠다.

 

Spring과 관련 라이브러리 비교 – 스프링시큐리티 구조상의 문제점?

스프링 시큐리티는 잘 만들어진 보안 프레임워크이긴한데…

스프링을 A등급이라고하면 시큐리티는  B등급 이상으로 점수를 주긴 싫다. 스프링 소셜은 C등급?

개념적인 부분에서는 좋을지 몰라도 사용자 입장에서는 아쉬운 부분이 많이 보인다. 구조가 직관적으로 이해하기 힘들기도 하고…

 

<http>를 이용해서 설정을 쉽게 해 주는것도 좋지만 이로 인해서 구조 파악과 커스터마이징이 더 힘들어진다.

기본 코드가 너무 데이터베이스를 활용하는데에만 치중되어 있고 구현이 되어 있는 부분이 많다. 인터페이스나 구조정도만 제공되어야 할 것 같은 부분에 데이터베이스를 사용하는 구현체들이 박혀있어서 이를 대체하기가 힘들다. 특히 <http>를 사용하는 경우에는 자동화가 진행 돼 버려서 더 불편해진다.

아니면 내가 제대로 파악하지 못한걸지도…?

어쨌든 이런 부분들 일부를 수정해서 만들어볼 계획.

 

 

SpringSecurity스프링시큐리티 로그인 수동처리 Manually Login

1. 간단하다

콘텍스트 홀더를 불러서 userDetails를 저장해준다. 어차피 시큐리티의 로그인 프로세스는 UserDetails에 필요한 정보를 디비나 기타 등등에서 가져와서 UserDetails구현체를 생성해가지고 시큐리티에서 관리하는 세션에 저장해주는 것이기 때문에… 이걸 간략하게 처리하는 것과 같다.

//UserDetails생성하는 코드를 사용해서 디테일즈 받아오기
UserDetails userDetails = userDetailsService.loadUserByUsername(account.getEmail());
//시큐리티 콘텍스트 홀더에 저장			SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()));

2. 스텍오버플로우에서 발견했던건데… 잘 안된다.

AuthenticationMAnager에서 인증이 실패한다. 정상적인 로그인 프로세스를 타는 방법이긴 하지만 암호화 되어있는 password를 입력해야하는데 여기서 틀린 것 같다. 맞는 패스워드를 넣는다면 성공할 것 같다. 맞는 것 같으니 테스트는 생략한다.

			UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("username", "password", "authorities");

			// Authenticate the user
			Authentication authentication = authenticationManager.authenticate(authRequest);
			SecurityContext securityContext = SecurityContextHolder.getContext();
			securityContext.setAuthentication(authentication);

			// Create a new session and add the security context.
			HttpSession session = request.getSession(true);
			session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);