자바 웹 Model과 Spring Security

Dear·2025년 7월 4일

TIL

목록 보기
55/74

💙 Model 객체

Spring MVC에서 Controller가 처리한 결과 데이터를 뷰(View)로 전달하기 위해 사용하는 객체

  • ModelMap<String, Object> 형태로 데이터를 저장한다.
  • Model, ModelMap, ModelAndView 중 하나를 사용한다.
  • HTML에서 ${속성명} 으로 접근 가능하다.
메서드설명
addAttribute(String key, Object value)단일 데이터를 추가할 때 사용합니다. Key를 기준으로 값을 저장합니다.
addAllAttributes(Map<String, ?> map)여러 데이터를 한 번에 추가할 수 있습니다. Map에 있는 모든 엔트리를 모델에 넣습니다.
mergeAttributes(Map<String, ?> map)addAllAttributes와 비슷하지만, 기존 키가 이미 존재하면 덮어쓰지 않고 유지합니다. 즉, 병합(Merge)입니다.
@GetMapping("/example")
public String example(Model model) {
    model.addAttribute("title", "Model 설명");
    
    Map<String, Object> map = new HashMap<>();
    map.put("author", "관리자");
    map.put("views", 123);
    
    model.addAllAttributes(map); // author, views 추가

    Map<String, Object> mergeMap = new HashMap<>();
    mergeMap.put("title", "다른 제목"); // 기존 "title"이 있으므로 병합 시 무시됨
    mergeMap.put("likes", 99);

    model.mergeAttributes(mergeMap); // "likes"는 추가되고, "title"은 유지됨

    return "modelPage";
}

Model

  • 인터페이스 (org.springframework.ui.Model)
  • 가장 많이 사용하는 방식
  • addAtribute() 메소드로 데이터 저장
  • 뷰 이름은 String으로 반환
@GetMapping("/user")
public String gerUser(Model model) {
    model.addAttribute("name", "짱구");
    return "viewPage";  // 뷰 이름
}

ModelMap

  • java.util.Map을 상속한 객체
  • 키-값 쌍으로 저장
  • Model보다 유연하고, put() 사용 가능
  • 뷰 이름은 String으로 반환
@GetMapping("/user")
public String gerUser(ModelMap modelMap) {
    modelMap.put("name", "짱구");
    return "viewPage";
}

ModelAndView

  • 뷰 이름과 데이터(Model)를 동시에 설정
  • 객체 하나에 뷰 이름 + 모델 데이터를 함께 설정
  • 메소드 반환 타입이 ModelAndView
@GetMapping("/modelandview")
public ModelAndView gerUser() {
    ModelAndView mav = new ModelAndView("viewPage");
    mav.addObject("name", "짱구");
    return mav;
}
항목ModelModelMapModelAndView
타입인터페이스 (Model)클래스 (ModelMap extends HashMap)클래스 (ModelAndView)
뷰 이름 지정return "view"return "view"new ModelAndView("view")
데이터 추가 방법addAttribute("key", value)put("key", value)addObject("key", value)
선언 위치메서드 파라미터메서드 파라미터반환 타입으로 사용
추천 사용 용도단순 데이터 전달Model과 유사, 유연한 Map 사용뷰와 데이터를 함께 설정하고 싶을 때

사용 시점

상황추천 방식
가장 기본적인 컨트롤러 설계Model
Map 스타일로 유연하게 쓰고 싶을 때ModelMap
데이터 + 뷰 이름을 명시적으로 반환하고 싶을 때ModelAndView

흐름

요청 -> Controller -> Modewl에 데이터 담기 -> View 렌더링

컨트롤러는 비즈니스 로직 처리 후 그 결과 데이터를 뷰(View)에 전달해야 하는데, 그 전달 도구가 Model이다.

💙 Spring Security

Spring 기반 애플리케이션의 보안(인증, 인가)을 담당하는 프레임워크

웹 애플리케이션에서 로그인, 권한 관리, CSRF 보호, 세션 관리 같은 보안 기능을 쉽게 구현할 수 있게 도와준다.

구분설명
인증 (Authentication)사용자가 누구인지 확인 (ex. 로그인)
인가 (Authorization)인증된 사용자가 무엇을 할 수 있는지 결정 (ex. 관리자만 글 삭제 가능)
Filter 기반 구조SecurityFilterChain으로 요청을 감시하고 처리
비밀번호 암호화BCryptPasswordEncoder 등을 통해 안전하게 암호화
세션 관리로그인 유지, 세션 고정 보호 등 제공
CSRF 보호CSRF 공격을 막기 위한 기본 설정 포함
기본 로그인 화면 제공설정하지 않으면 기본 로그인 폼 자동 생성

동작 흐름

  1. 사용자가 로그인 요청
  2. UsernamePasswordAuthenticationFilter → 인증 시도
  3. UserDetailsService → 사용자 정보 로드
  4. AuthenticationManager → 인증 검증
  5. SecurityContextHolder → 인증 정보 저장
  6. 접근 제어 (인가)
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .requestMatchers("/", "/login", "/css/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(withDefaults())  // 기본 로그인 폼 사용
            .logout(withDefaults());

        return http.build();
    }
}

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 실제로는 DB에서 사용자 조회
        return User.withUsername("user")
                   .password(passwordEncoder().encode("1234"))
                   .roles("USER")
                   .build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
어노테이션설명
@EnableWebSecuritySpring Security 설정을 활성화
@PreAuthorize("hasRole('ADMIN')")메서드 실행 전에 권한 체크
@Secured("ROLE_USER")특정 역할에만 접근 허용
@WithMockUser테스트 시 가짜 사용자 설정

💙 세션 고정 공격 (Session Fixation)

공격자가 세션 ID를 미리 정해놓고, 사용자가 그 세션을 쓰게 만든 뒤 해당 세션으로 접근하는 공격

예시

  1. 공격자가 임의의 세션 ID를 가진 링크를 준비 (https://example.com?JSESSIONID=abc123)
  2. 피해자에게 그 링크를 클릭하게 유도 (예: 피싱 메일, 게시판 등)
  3. 피해자가 로그인하면 해당 세션 ID(abc123)는 인증된 세션이 됨
  4. 공격자는 자신이 알고 있는 동일한 세션 ID(abc123)로 접근해서 로그인된 사용자처럼 행동

-> 공격자는 정상 로그인 없이 인증된 사용자가 되며 세션이 유지되는 동안 피해자의 권한으로 정보 탈취, 조작이 가능하다.

방지

Spring Security는 로그인 시 기존 세션을 무효화하고 새로운 세션을 생성함으로써 세션 고정 공격을 기본적으로 방지한다.

http
    .sessionManagement()
    .sessionFixation().migrateSession(); // 기본값
  • migratesSession (기본값) : 기존 세션 무효화 -> 새 세션 생성, 속성 복사
  • newSession : 아예 속성 복사 없이 새 세션 생성
  • none : 세션 고정 방지 안 함 (취약할 수 있다)

🤍 회고

오늘은 모델 객체와 Spring Security의 개념에 대해 공부했다.
Model, ModelMap, ModelAndView는 모두 컨트롤러에서 뷰로 데이터를 전달할 때 사용되며, 상황에 따라 적절히 선택하여 사용할 수 있다. 특히 Model이 가장 직관적이고 자주 사용된다는 점에서 잘 익혀두는 것이 중요하다고 느꼈다.
또한 Spring Security에서는 인증과 인가를 어떻게 처리하는지, 기본 로그인 설정 외에도 세션 고정 공격 같은 보안 이슈를 어떻게 예방하는지에 대해서도 알게 되었다. 단순히 로그인만 구현하는 것이 아니라 보안까지 고려한 설계가 필요하다는 것을 느꼈다.

profile
친애하는 개발자

0개의 댓글