1. 클라이언트의 요청을 디스패처 서블릿이 받음
  2. 요청 정보를 통해 요청을 위임할 컨트롤러를 찾음
  3. 요청을 컨트롤러로 위임할 핸들러 어댑터를 찾아서 전달함
  4. 핸들러 어댑터가 컨트롤러로 요청을 위임함
  5. 비지니스 로직을 처리함
  6. 컨트롤러가 반환값을 반환함
  7. HandlerAdapter가 반환값을 처리함
  8. 서버의 응답을 클라이언트로 반환함

'☕JAVA의 모든것' 카테고리의 다른 글

Transaction Test  (0) 2024.04.25
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />  (0) 2024.04.25
SecurityContextHolder  (0) 2024.04.24
SCOPE  (0) 2024.04.24
import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import edu.ex.mapper.BoardMapper;
import edu.ex.vo.BoardVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class TransactionTestService {

	@Autowired
	private BoardMapper mapper;

	// Test1 : 트랜잭션 내에서 두 개의 삽입 작업을 시뮬레이션함. 첫 번째 삽입이 성공하면 롤백안함.
	@Transactional
	public void TransactionTest1() {

		log.info("TransactionTest1()..");

		BoardVO boardVO = new BoardVO();
		boardVO.setBcontent("트랜잭션1");
		boardVO.setBname("트랜잭션1");
		boardVO.setBtitle("트랜잭션1");

		mapper.insertBoard(boardVO);

		BoardVO boardVO2 = new BoardVO();
		boardVO2.setBcontent("트랜잭션2");
		boardVO2.setBname("트랜잭션2");
		boardVO2.setBtitle("트랜잭션2");

		mapper.insertBoard(boardVO2);

	}

	// Test2 : 트랜잭션 내에서 두 개의 삽입 작업을 시도하지만, 두 번째 삽입 작업 직전에 일부러 예외를 발생시켜 롤백될 수 있도록 함.
	public void TransactionTest2() {

		log.info("TransactionTest2()..");

		BoardVO boardVO = new BoardVO();
		boardVO.setBcontent("트랜잭션1");
		boardVO.setBname("트랜잭션1");
		boardVO.setBtitle("트랜잭션1");

		mapper.insertBoard(boardVO);

		BoardVO boardVO2 = new BoardVO();
		boardVO2.setBcontent("트랜잭션2");
		boardVO2.setBname("트랜잭션2");
		boardVO2.setBtitle("트랜잭션2");

		// 일부러 트랜잭션을 위한 테스트로 null 값 셋팅
		boardVO2 = null;
		mapper.insertBoard(boardVO2);

	}

	// Test3 : 트랜잭션 내에서 두 개의 삽입 작업을 시도하지만, 
	// 두 번째 삽입 작업 직전에 일부러 예외를 발생시켜 롤백될 수 있도록 함. 
    // 이 메서드에서는 @Transactional 어노테이션이 메서드에 적용함.
	@Transactional
	public void TransactionTest3() {

		log.info("TransactionTest3()..");

		BoardVO boardVO = new BoardVO();
		boardVO.setBcontent("트랜잭션3");
		boardVO.setBname("트랜잭션3");
		boardVO.setBtitle("트랜잭션3");

		mapper.insertBoard(boardVO);

		BoardVO boardVO2 = new BoardVO();
		boardVO2.setBcontent("트랜잭션3");
		boardVO2.setBname("트랜잭션3");
		boardVO2.setBtitle("트랜잭션3");

		boardVO2 = null;
		mapper.insertBoard(boardVO2);

	}

	// Test4 : RuntimeException을 발생시켜 트랜잭션을 롤백하는 경우를 시뮬레이션함.
	// 트랜잭션 내에서 데이터를 삽입한 후, 특정 조건에서 의도적으로 런타임 예외를 발생시킴. 
    // 이러한 경우 트랜잭션은 롤백되며, 이전에 삽입한 데이터도 롤백됨.
	@Transactional 
	public void TransactionTest4() {

		log.info("TransactionTest4()..");

		BoardVO boardVO = new BoardVO();
		boardVO.setBcontent("트랜잭션4");
		boardVO.setBname("트랜잭션4");
		boardVO.setBtitle("트랜잭션4");

		mapper.insertBoard(boardVO);

		throw new RuntimeException("RuntimeException for rollback");

	}
    
	// Test5 : SQLException을 발생시켜도 롤백되지 않는 경우를 시뮬레이션함. 
    // 트랜잭션 내에서 데이터를 삽입한 후, 특정 조건에서 의도적으로 SQL 예외를 발생시킴. 
    // 이 예외는 rollbackFor 옵션에 명시되지 않았으므로 롤백되지 않고, 데이터베이스에는 삽입된 데이터가 남게 됨.
	// CheckedException 테스트(롤백안함)
	@Transactional 
	public void TransactionTest5() throws SQLException {

		log.info("TransactionTest5()..");

		BoardVO boardVO = new BoardVO();
		boardVO.setBcontent("트랜잭션5");
		boardVO.setBname("트랜잭션5");
		boardVO.setBtitle("트랜잭션5");

		mapper.insertBoard(boardVO);

		throw new SQLException("SQLException for rollback");

	}
		
	// Test6 : @Transactional의 rollbackFor 옵션을 이용하면 Rollback이 되는 클래스를 지정가능함.
	// Exception예외로 롤백을 하려면 @Transactional(rollbackFor = Exception.class)
	// 여러개의 예외를 지정할 하려면 @Transactional(rollbackFro = {RuntimeException.class, Exception.class})
	// @Transactional 어노테이션의 rollbackFor 옵션을 사용하여 SQLException이 발생했을 때 트랜잭션을 롤백하는 경우를 시뮬레이션함. 
	// SQLException이 발생하면 해당 트랜잭션은 롤백되며, 이전에 삽입한 데이터도 롤백.
	@Transactional(rollbackFor = Exception.class) 
	public void TransactionTest6() throws SQLException {

		log.info("TransactionTest6()..");

		BoardVO boardVO = new BoardVO();
		boardVO.setBcontent("트랜잭션5");
		boardVO.setBname("트랜잭션5");
		boardVO.setBtitle("트랜잭션5");

		mapper.insertBoard(boardVO);

		throw new SQLException("SQLException for rollback");
		
	}
	
	// Test7 : @Transactional 어노테이션의 rollbackFor 옵션을 사용하여 SQLException이 발생했을 때 트랜잭션을 롤백하는 경우를 시뮬레이션함. 
	// SQLException이 발생하면 해당 트랜잭션은 롤백되며, 이전에 삽입한 데이터도 롤백됨. 
    // 이전과는 달리 SQLException에 대한 롤백이 명시적으로 지정.
	@Transactional(rollbackFor = SQLException.class) 
	public void TransactionTest7() throws SQLException {

		log.info("TransactionTest7()..");

		BoardVO boardVO = new BoardVO();
		boardVO.setBcontent("트랜잭션7");
		boardVO.setBname("트랜잭션7");
		boardVO.setBtitle("트랜잭션7");

		mapper.insertBoard(boardVO);

		throw new SQLException("SQLException for rollback");

	}
}

'☕JAVA의 모든것' 카테고리의 다른 글

Dispatcher Servlet  (0) 2024.04.29
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />  (0) 2024.04.25
SecurityContextHolder  (0) 2024.04.24
SCOPE  (0) 2024.04.24
더보기
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
대체 왜 필요해서 스프링시큐리티에서 넣어주는 걸까?

 

form 태그의 method 방식이 "POST"일때만 넣어줌.

"GET"방식일때는 안넣어줌.

 

CSRF를 막기 위해서 넣어준 코드임!!!

 

name="${_csrf.parameterName}" value="${_csrf.token}"

 

crsf token은 매번 value값이 바뀌고 hidden으로 포함되어 들어가기 때문에 

공격자 입장에서는 고정된 쿼리문만 전송해서는 더이상 명령이 작동하지 않고 

매번바뀌는 csrf token값을 그때그때 찍어서 맞춰야함 사실상 완전방어!!!

 

 CSRF(Cross-site request forgery) 공격과 토큰


 스프링 시큐리티에서 POST 방식을 이용하는 경우 기본적으로 CSRF 토큰이라는 것을 이용하게 된다. 별도의 설정이 없다면 스프링 시큐리티가 적용된 사이트의 모든 POST 방식에는 CSRF 토큰이 사용되는데 '사이트간 위조 방지'를 목적으로 특정한 값의 토큰을 사용하는 방식이다.

CSRF 공격은 '사이트간 요청 위조'라고 번역될 수 있다. 서버에서 받아들이는 정보가 특별히 사전 조건을 검증하지 않는다는 단점을 이용하는 공격이다. 

예를 들어 A라는 사이트가 존재한다고 가정하고, A 사이트에는 특정 사용자의 등급을 변경하는 URI가 존재하고 파라미터가 필요하다는 것을 공격자가 알았을 때, 공격자는 A 사이트의 관리자(피해자)가 자주 방문하는 B 사이트에 <img> 태그나 <form> 태그를 이용해서 위의 URI를 추가한 게시물을 작성한다. A 사이트의 관리자(피해자)는 자신이 평상시 방문하던 B 사이트를 방문하게 되고 공격자가 작성한 게시물을 보게 된다. 이때 태그 등에 사용된 URI가 호출되고 서버에서 로그인한 관리자의 요청에 의해서 공격자는 admin 등급의 사용자로 변경된다.
A 사이트 관리자는 자신이 관리하던 A 사이트에 로그인이 되어 있는 상태라면 A 사이트의 서버 입장에서는 로그인한 사용자의 정상적인 요청으로 해석된다. 
CSRF 공격은 서버에서 받아들이는 요청을 해석하고 처리할 때 어떤 출처에서 호출이 징행되엇는지 따지지 않기 때문에 생기는 허점을 노리는 공격 방식이다.

CSRF는 현실적으로 하나의 사이트 내에서도 가능하다. 공격을 막기 위해서는 여러 방식이 존재한다. 

 1) CSRF 공격 자체가 사용자의 요청에 대한 출처를 검사하지 않아서 생기는 허점이기 때문에 사용자의 요청에 대한 출처를 의미하는 referer 헤더를 체크하거나 
 2) REST 방식에서 사용되는 PUT, DELETE와 같은 방식을 이용하는 것이 있다.

 

 CSRF 토큰


CSRF 토큰은 사용자가 임의로 변하는 특정한 토큰값을 서버에서 체크하는 방식이다. 서버에서 브라우저에 데이터를 전송할 때 CSRF 토큰을 같이 전송한다. 사용자가 POST 방식 등으로 특정한 작업을 할 때는 브라우저에서 전송된 CSRF 토큰의 값과 서버가 보관하고 있는 토큰의 값을 비교한다. 만일 CSRF 토큰 값이 다르다면 작업을 처리하지 않는 방식이다. 서버에서 생성하는 토큰은 일반적으로 난수를 생성해서 공격자가 패턴을 찾을 수 없도록 한다.
 아무튼 공격자 입장에서는 CSRF 공격을 하려면 변경되는 CSRF 토큰의 값을 알아야만 하기 때문에 고정된 내용의 태그 등을 이용할 수 없게 된다.

 

 

'☕JAVA의 모든것' 카테고리의 다른 글

Dispatcher Servlet  (0) 2024.04.29
Transaction Test  (0) 2024.04.25
SecurityContextHolder  (0) 2024.04.24
SCOPE  (0) 2024.04.24

SecurityContextHolder는 Spring Security 프레임워크에서 중요한 클래스 중 하나입니다. Spring Security는 인증(Authentication)과 인가(Authorization)를 처리하는 데 사용되는 강력한 보안 프레임워크입니다.

SecurityContextHolder는 현재 인증된 사용자의 보안 컨텍스트를 제공합니다. 이 컨텍스트에는 현재 인증된 사용자의 정보와 권한이 포함됩니다. 주로 스프링 애플리케이션에서 사용자의 보안 정보를 확인하거나 변경하는 데 사용됩니다.

SecurityContextHolder는 주로 다음 두 가지 SecurityContext를 관리합니다:

  1. SecurityContext:
    • SecurityContext는 현재 스레드에 대한 보안 정보를 포함하는 인터페이스입니다.
    • 주로 Authentication 객체를 포함하고 있으며, 이 객체는 현재 인증된 사용자의 정보와 권한을 나타냅니다.
  2. ThreadLocalSecurityContextHolderStrategy:
    • SecurityContextHolder는 기본적으로 ThreadLocalSecurityContextHolderStrategy를 사용하여 현재 스레드의 SecurityContext를 관리합니다.
    • 이 전략은 현재 스레드의 SecurityContext를 스레드 로컬 변수(Thread Local Variable)에 저장하여 스레드 간에 공유되지 않도록 보장합니다.

SecurityContextHolder를 사용하여 현재 사용자의 보안 정보에 액세스하거나 변경할 수 있습니다. 예를 들어, 현재 사용자의 인증 객체를 얻으려면 다음과 같이 사용할 수 있습니다:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

Spring Security는 웹 애플리케이션에서 보안을 구현하는 데 널리 사용되며, SecurityContextHolder는 이러한 보안 구현에서 핵심적인 역할을 합니다.

'☕JAVA의 모든것' 카테고리의 다른 글

Dispatcher Servlet  (0) 2024.04.29
Transaction Test  (0) 2024.04.25
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />  (0) 2024.04.25
SCOPE  (0) 2024.04.24
웹 어플리케이션은 Page, Request,Session, Application 이라는 4개의 영역(Scope)을 가진다.
  1. Page Scope - 해당 페이지가 실행되는 동안만 유지되는 영역.
  2. Request Scope - http 요청을 WAS가 받아서 웹 브라우저에게 응답할 때까지 변수값을 유지하고자 할 경우 사용 되는 영역.
  3. Session Scope (세션 스코프) - 웹 브라우저별로 변수를 관리하고자 할 경우에 사용되는 영역.
  4. Application Scope (어플리케이션 스코프) - 서버가 가동되는 순간부터 서버가 종료되는 순간까지의 모든 영역.

 

출처 http://inheritingjava.blogspot.kr/2011/04/chapter-42-scope-of-javabeans-in-jsp.html

 

 

Page Scope

  • PageContext 추상 클래스를 사용한다.
  • JSP 페이지에서 pageContext라는 내장 객체로 사용 가능 하다.
  • forward가 될 경우 해당 Page scope에 지정된 변수는 사용할 수 없다.
  • 마치 지역변수처럼 사용된다는 것이 다른 Scope들과 다릅니다.
  • jsp에서 pageScope에 값을 저장한 후 해당 값을 EL표기법 등에서 사용할 때 사용됩니다.
  • 지역 변수처럼 해당 jsp나 서블릿이 실행되는 동안에만 정보를 유지하고자 할 때 사용됩니다.

Request Scope

  • http 요청을 WAS가 받아서 웹 브라우저에게 응답할 때까지 변수값을 유지하고자 할 경우 사용한다.
  • HttpServletRequest 객체를 사용한다.
  • JSP에서는 request 내장 변수를 사용한다.
  • 서블릿에서는 HttpServletRequest 객체를 사용한다.
  • 값을 저장할 때는 request 객체의 setAttribute()메소드를 사용한다.
  • 값을 읽어 들일 때는 request 객체의 getAttribute()메소드를 사용한다.
  • forward 시 값을 유지하고자 사용한다.

Session Scope

  • 웹 브라우저별로 변수를 관리하고자 할 경우 사용한다.
  • 웹 브라우저간의 탭 간에는 세션정보가 공유되기 때문에, 각각의 탭에서는 같은 세션정보를 사용할 수 있다.
  • HttpSession 인터페이스를 구현한 객체를 사용한다.
  • JSP에서는 session 내장 변수를 사용한다.
  • 서블릿에서는 HttpServletRequest의 getSession()메소드를 이용하여 session 객체를 얻는다.
  • 값을 저장할 때는 session 객체의 setAttribute()메소드를 사용한다.
  • 값을 읽어 들일 때는 session 객체의 getAttribute()메소드를 사용한다.
  • 장바구니처럼 사용자별로 유지가 되어야 할 정보가 있을 때 사용한다.

 

'☕JAVA의 모든것' 카테고리의 다른 글

Dispatcher Servlet  (0) 2024.04.29
Transaction Test  (0) 2024.04.25
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />  (0) 2024.04.25
SecurityContextHolder  (0) 2024.04.24

+ Recent posts