개인이 자신을 식별(identify)하고 인증(authenticate)하여 컴퓨터 시스템에 액세스하는 프로세스
자신이 누구라고 주장하는 주체(principal)를 확인하는 프로세스

단방향 해시 함수는 임의의 길이를 같은 길이로 바꾸다 보니까 충돌이 일어날 수 있다.
그래서 역으로 바꾸는 것이 안된다.

session을 사용할 때 server를 두대를 두면 session repository가 따로 필요하다.
session repository를 db를 쓰면 느리고 비싸다.
session을 참조할 수 있게 cookie에 session 아이디를 남겨놓는다.
session에는 비밀번호를 남기면 안된다.
이유는 server가 해킹당하면 악용 위험이 있기 때문이다.
쿠키는 보통 사용자의 브라우저에 남겨도 해가되지 않는 정보를 남긴다.
세션은 서버에서 서비스에 필요한 정보를 매번 db에서 가져오지 않기 위한 값을 저장한다.
Spring Security가 좋은 점은 선언적이고 비 침투적이기 때문이다.
웹 같은 경우는 filter를 기반으로 되어있고 method security는 AOP를 기반으로 구현되어 있다.
Spring Security는 원래 Spring Framework랑 따로 만들어졌다.
보통 cache를 사용하는 이유는 서버의 부담을 줄이기 위해서이다.
HTTP 헤더에 Cache-Control에 있는 cache는 브라우저에 있는 cache를 의미하는 것이다.
X-는 공식 헤더가 아니라서 해석 못하는 브라우저가 있을 수도 있다.
http
.headers()
.defaultsDisabled()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
http
.headers()
.cacheControl()/*.disable()*/
X-Content-Type-Options: nosniff
http
.headers()
.contentTypeOptions()/*.disable()*/
X-Frame-Options: DENY
http
.headers()
.frameOptions()/*.deny()*/.sameOrigin()
X-XSS-Protection: 1; mode=block
http
.headers()
.xssProtection
/*.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)*/.disable()
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
http
.headers()
.httpStrictTransportSecurity()
.includeSubdomains(true)
.maxAgeSeconds(31536000) /* 365일 */
해당 헤더는 https요청을 강제하는 헤더이기 때문에 http를 지원하는 경우 설정하면 매우 치명적으로 작용하는 헤더이다.
http
.csrf()
/*.disable()*/
spring
security:
user:
name: academy
password: 12345
roles:
- MEMBER
| 표현식 | 설명 |
|---|---|
| hasRole('권한'), hasAuthority('권한') | 해당 권한을 가졌는가? |
| hasAnyRole('권한1', '권한2'), hasAnyAuthority('권한1', '권한2') | 지정한 권한 중 하나라도 가졌는가? |
| permitAll() | 모두 허용 |
| denyAll() | 모두 거부 |
| isAnonymous() | 익명 사용자인가? |
| isAuthenticated() | 인증된 사용자인가? |
role과 authority의 차이는 role은 권한 앞에 ROLE을 붙여서 매칭하고 authority는 입력받은 권한 자체로 매칭을 한다.
authority의 앞에 ROLE을 붙이는 것이 관례이다.

public interface Authentication {
Object getPrincipal(); // 주체
Object getCredentials(); // 자격증명
Collection<? extends GrantedAuthority> getAuthorities();
// ...
}
interface Authentication {
Object getPrincipal();
}
public interface UserDetails extends Serializable {
String getUsername();
String getPassword();
Collection<? extends GrantedAuthority> getAuthorities();
// ...
}
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
// ...
}
@Bean
public InMemoryUserDetailsManager userDetailsService() {
return new InMemoryUserDetailsManager(User.withUsername("user")
.password("{noop}user")
.authorities("ROLE_USER")
.build());
}
http
.formLogin()
.loginPage("/login/form")
.usernameParameter("name")
.passwordParameter("pwd")
.loginProcessingUrl("/login/process")
.failureHandler(loginFailureHandler())
http
.logout()
.deleteCookies("A-COOKIE", "B-COOKIE")
.invalidateHttpSession(true)
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.addLogoutHandler(logoutHandler())
http
.exceptionHandling()
.accessDeniedPage("/error/403")
<html lang="ko" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<!-- ... -->
</html>
<li sec:authorize="hasRole('ROLE_MEMBER')">
<li sec:authorize-url="/public-project/2">
<div sec:authentication="principal.username" />
<form method="post" action="/login/process">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<!-- ... -->
</form>
<!DOCTYPE html>
<html>
<head>
<title>CSRF Protected JavaScript Page</title>
<meta charset="UTF-8">
<meta id="_csrf" name="_csrf" th:content="${_csrf.token}" />
<meta id="_csrf_header" name="_csrf_header" th:content="${_csrf.headerName}" />
<script type="text/javascript" language="javascript">
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
var csrfToken = $("meta[name='_csrf']").attr("content");
</script>
</head>
<!-- ... -->


public class FilterChainProxy extends GenericFilterBean {
private List<SecurityFilterChain> filterChains;
// ...
}

public interface SecurityFilterChain {
boolean matches(HttpServletRequest request);
List<Filter> getFilters();
}
package org.springframework.security.config.http;
enum SecurityFilters {
FIRST(Integer.MIN_VALUE),
CHANNEL_FILTER,
SECURITY_CONTEXT_FILTER,
CONCURRENT_SESSION_FILTER,
WEB_ASYNC_MANAGER_FILTER,
HEADERS_FILTER,
CORS_FILTER,
CSRF_FILTER,
LOGOUT_FILTER,
X509_FILTER,
PRE_AUTH_FILTER,
CAS_FILTER,
FORM_LOGIN_FILTER,
OPENID_FILTER,
LOGIN_PAGE_FILTER,
DIGEST_AUTH_FILTER,
BEARER_TOKEN_AUTH_FILTER,
BASIC_AUTH_FILTER,
REQUEST_CACHE_FILTER,
SERVLET_API_SUPPORT_FILTER,
JAAS_API_SUPPORT_FILTER,
REMEMBER_ME_FILTER,
ANONYMOUS_FILTER,
SESSION_MANAGEMENT_FILTER,
EXCEPTION_TRANSLATION_FILTER,
FILTER_SECURITY_INTERCEPTOR,
SWITCH_USER_FILTER,
LAST(Integer.MAX_VALUE);
}
ExceptionTranslationFilter는 새로운 인증 방법을 구현하였을 때 테스트로 사용하는 경우도 있다.
http
.addFilterAt(yourFilter, CasAuthenticationFilter.class)
.addFilterBefore(myFilter1, UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(myFilter2, CsrfFilter.class)