반응형
반응형

📝양자컴퓨터

양자역학의 원리를 활용해 계산을 수행하는 새로운 방식의 컴퓨터입니다.

전통적인 컴퓨터가 사용하는 비트(bit) 대신, 양자 컴퓨터는 양자 비트(큐비트, qubit)를 사용해 정보를 처리합니다.

큐비트는 0과 1 사이의 모든 상태를 동시에 가질 수 있습니다.

 

예를들면 3개의 고전 비트는 한 번에 하나의 상태(예: 000, 001, ... 등 8개 중 하나)를 표현하지만, 3개의 큐비트는 한 번에 모든 상태를 동시에 표현할 수 있습니다. 이를 통해 양자 컴퓨터는 병렬로 여러 계산을 동시에 수행할 수 있습니다. 큐비트가 늘어날수록 연산 능력이 지수적으로 증가합니다.

 

양자 컴퓨터는 확률적으로 정답을 찾아갑니다. 확률이 높다고 무조건 정답은 아니지만 이를 보완하기 위해 매우 많은 시도를 동시에 진행한다. (검산과정) → 간섭이 많을 수록 확률이 높다 (정답 가능성이 매우 높음)

 

 

📝Qubit(큐비트)

정보를 저장하고 처리하는 양자적 단위

 

 

📝 양자 푸리에 변환(QFT)

양자 푸리에 변환의 경우 일상생활 문제를 해결하기 위한 양자역학의 시도입니다. 입력 데이터(시간 또는 공간에 따른 함수)를 주파수 기반의 성분으로 분해하는 과정을 의미합니다.

주기성 탐지, 최적화 문제 해결에 탁월하다 주 사용 분야는 양자 컴퓨팅이며 상태를 주파수 영역으로 변환시켜 사용한다.  주기가 있는 즉, 주기가 있다는 건 특징이 있다는 것이고 특징이 있는 곳에 활용하기 좋다는 말입니다.

 

 

📝쇼어 알고리즘

1994년 피터 쇼어(Peter Shor)가 제안한 양자 알고리즘으로, 큰 정수를 빠르게 소인수분해하는 방법입니다.

양자컴퓨터에서 중요한데 고전 컴퓨터에서는 소인수분해는 매우 시간이 많이 걸리는 작업인데 특히 큰 수는 소인수 분해가 사실상 불가능합니다. 하지만 해당 알고리즘은 이 문제를 효율적으로 해결할 수 있습니다.

 

RSA는 소인수 분해의 "어려움"을 기반으로 한 암호화 체계로 보안에 문제를 일으킬 수도 있다는 말이 있습니다.

 

 

📝그로버 알고리즘

양자 컴퓨팅에서 사용되는 검색 알고리즘으로, 미지의 데이터베이스에서 원하는 항목을 빠르게 찾는 문제를 해결합니다. 이는 고전적인 검색 알고리즘보다 제곱근 속도로 빠릅니다

 

 

🔗 참고 및 출처

https://www.youtube.com/watch?v=iWnqT_Zv6q8

https://www.youtube.com/watch?v=ScBscK0wEI4

 

반응형
반응형

📝인공지능

컴퓨터가 인간처럼 사고, 학습, 문제를 해결, 판단할 수 있도록 설계된 기술입니다.

 

📝머신러닝

데이터를 학습하여 특정 작업을 수행할 수 있도록 컴퓨터를 훈련시키는 기술입니다. 인간은 데이터를 넣어주고 학습방법에 따라 훈련시킵니다. 예를 들면 고양이 사진을 주고 고양이 특징을 알려줬을 때 다른 고양이 사진을 주면 고양이라고 판단합니다.

 

훈련기술은 아래와 같습니다.

 

  • 지도학습
    • 입력 데이터와 정답이 주어진 상태에서 학습 → 이메일 스팸 필터
  • 비지도학습
    • 정답이 없는 데이터를 분석하고 패턴을 학습 → 이미지 분류
  • 강화학습
    • 보상을 기반으로 최적의 행동을 학습 → 알파고(바둑)

 

 

📝딥러닝

머신러닝의 하위 분야로 인공 신경망을 기반으로 데이터를 학습시키는 기술입니다. 머신러닝과 달리 사람의 개입 없이 중요한 특징을 알아서 추출합니다. 예를 들면 고양이 사진을 여러개를 주면 알아서 특징을 파악하고 다른 고양이 사진을 줬을 때 얘가 고양인지 파악할 수 있습니다.

 

  • 입력층
    • 입력데이터를 신경망에 전달하는 첫번째 층이다. 데이터만 전달하며 함수나 가중치 계산은 없다.
  • 은닉층
    • 입력 데이터를 변환하고 학습하는 신경망의 중간층이다. 은닉층이 많아질수록 더 복잡한 패턴 학습이 가능하다. 일반적으로 그렇지만 많은 시도를 해서 자기가 원하는 최적의 결과를 얻을때까지 해야한다. (사실 나도 안 해봐서 잘 모름)
  • 출력층
    • 신경망의 최종 결과를 출력하는 층이다.

 

📝머신러닝 vs 딥러닝

특징 머신러닝 딥러닝
데이터 처리 사람이 데이터를 분석하고 특징을 수동 정의 신경망이 데이터를 입력받아 특징을 자동으로 추출
데이터 요구량 비교적 적은 데이터로도 학습 가능 방대한 데이터 필요 (방대할 수록 성능이 올라간다)
컴퓨팅 자원 적은 연산 자원으로도 학습 가능 고성능 GPU 필요
비정형 데이터 처리 주로 구조화된 데이터(엑셀, 테이블) 처리에 적합 이미지, 텍스트, 음성 등 비정형 데이터를 처리 가능
특징 추출 사람이 직접 특징을 추출하게끔 설계 자동으로 특징 추출

 

 

📝LLM (대규모 언어 모델)

대규모 데이터로 학습된 언어 모델로, 자연어를 이해하고 생성하는 데 사용됩니다. LLM은 특히 수십억에서 수조 개의 매개변수(parameters)를 가진 신경망 모델로, 복잡한 언어적 패턴을 학습할 수 있습니다.

 

📝생성형 AI

데이터를 학습하여 새로운 콘텐츠(텍스트, 이미지, 음악 등)를 생성할 수 있는 AI 기술입니다. LLM과 딥러닝 기술을 이용해 텍스트, 이미지, 음성 등을 생성합니다.

 

 

📝자연어 처리

인간의 언어(자연어)를 컴퓨터가 이해하고 생성하며 처리할 수 있도록 하는 기술입니다.

반응형
반응형

📝절차지향 vs 객체지향

절차지향 vs 객체지향의 경우 인프콘에서 컨퍼런스한 내용을 기반으로 작성했습니다

 

절차지향과 객체지향에 차이를 설명하기에 앞서 예제를 준비했습니다. (Java 기반 코드)

장바구니의 전체 금액 >= 할인 기준금액일 경우 할인 프로모션을 적용시키는 시스템을 만드려고 합니다.

 

절차지향의 경우는 아래와 같습니다

// 할인
public class Promotion {
    private Long cartId;
    private Long basePrice;
    
    public Money getBasePrice() {
    	return basePrice;
    }
    public void setCart(Long cartId) {
   	 this.cartId = cartId;
    }
}

// 장바구니
public class Cart {
    private List<CartLineItem> items = new ArrayList<>();
    
    public Long getTotalPrice() {
    	return items.stream().mapToLong(CartLineItem::getPrice).sum();
    }
    public int getTotalQuantity() {
    	return items.stream().mapToInt(CartLineItem::getQuantity).sum();
    }
}

// 할인 프로세스
public class PromotionProcess {
    public void apply(Promotion promotion, Cart cart) {
        if (isApplicableTo(promotion, cart)) {
            promotion.setCart(cart);
        }
    }
    private boolean isApplicableTo(Promotion promotion, Cart cart) {
    	return cart.getTotalPrice() >= promotion.getBasePrice();
    }
}

절차지향의 경우 할인, 장바구니의 데이터영역과 할인 프로세스를 처리하는 프로세스영역으로 나누어져있습니다.

 

 

객체지향의 경우는 아래와 같습니다.

// 할인 + 할인프로세스
public class Promotion {
    private Cart cart;
    private Long basePrice;
    
    public void apply(Cart cart) {
    	if (cart.getTotalPrice() >= basePrice) {
    	this.cart = cart;
    	}
    }
}

// 장바구니
public class Cart {
    private List<CartLineItem> items = new ArrayList<>();
    
    public Long getTotalPrice() {
    	return items.stream().mapToLong(CartLineItem::getPrice).sum();
    }
    public int getTotalQuantity() {
    	return items.stream().mapToInt(CartLineItem::getQuantity).sum();
    }
}

절차지향과 다르게 객체지향은 데이터와 프로세스 영역으로 나누어져있지 않습니다. 할인과 관련된 것들끼리 다 모여있고 장바구니 관련된 것끼리 다 모여있습니다.

 


절차지향과 객체지향의 차이를 이야기할 때는 변경이라는게 중요합니다. 어떤 변경에 어떤 방식이 유연한지에 대한 것입니다. 위에 예제 기반으로 더 진행하자면 이번에는 최소금액 <= 장바구니금액 <= 최대금액일 경우에 할인이 적용되게끔 변경해달라는 요청이 있을 때 처리하는 방법입니다.

 

 

절차지향의 경우 아래와 같습니다.

// 할인 적용 프로세스
public class PromotionProcess { 
    public void apply(Promotion promotion, Cart cart) {
        if (isApplicableTo(promotion, cart)) {
            promotion.setCart(cart);
        }
    }
    
    private boolean isApplicableTo(Promotion promotion, Cart cart) {
    	return cart.getTotalPrice() >= promotion.getMinPrice() 
        &&     cart.getTotalPrice() <= promotion.getMaxPrice()
    }
}

// 할인
public class Promotion {
    private Long cartId;
    private Long minPrice;
    private Long maxPrice;
    
    public Long getMinPrice() {
        return minPrice;
    }
    public Long getMaxPrice() {
    	return maxPrice;
    }
    public void setCart(Long cartId) {
        this.cartId = cartId;
    }
}

절차지향의 경우 할인 적용시킬 기준 금액인 최소금액과 최대금액을 추가시켰습니다. Promotion과 PromotionProcess 두군데에서 수정이 이루어졌습니다.

 

 

객체지향의 경우 아래와 같습니다.

public class Promotion {
    private Cart cart;
    private Long minPrice;
    private Long maxPrice;
    
    public void apply(Cart cart) {
    	if (cart.getTotalPrice() >= basePrice &&
    		cart.getTotalPrice() >= maxPrice) {
        	this.cart = cart;
    	}
    }
}

객체지향의 경우 Promotion에 Promotion관련 필드와 로직이 다 들어있기 때문에 Promoiton 한군데에서만 수정이 이루어졌습니다.

 


변경사항이 또 들어왔습니다. 이번에는 할인 조건을 하나 더 추가하는데 장바구니의 상품수  >= 프로모션 상품수일 경우 할인을 해줍니다. 할인을 받기 위해서는 설정한 프로모션 상품수보다 장바구니에 더 많이 담으면 할인을 해준다는 것이죠

 

 

절차지향의 경우 아래와 같습니다.

// 할인 프로세스
public class PromotionProcess {
    public void apply(Promotion promotion, Cart cart) {
        if (isApplicableTo(promotion, cart)) {
    		promotion.setCart(cart);
    	}
    }
    
    private boolean isApplicableTo(Promotion promotion, Cart cart) {
        switch (promotion.getConditionType()) {
            case PRICE:
            	return cart.getTotalPrice() >= promotion.getBasePrice();
            case QUANTITY:
                return cart.getTotalQuantity() >= promotion.getBaseQuantity
        }
    	return false;
    }
}

// 할인
public class Promotion {
    public enum ConditionType {
    	PRICE, QUANTITY
    }

    private Long cartId;
    private Long basePrice;
    private int baseQuantity;

    public ConditionType getConditionType() {
    	return conditionType;
    }
    public Money getBasePrice() {
   	 return basePrice;
    }
    public int getBaseQuantity() {
    	return baseQuantity;
    }	
    public void setCart(Long cartId) {
    	this.cartId = cartId;
    }
}

절차지향의 경우는 가격 또는 개수에 따른 할인 조건이 두개라서 CondtionType을 할인 모델에 추가시켰습니다. 그리고 할인을 위한 기준 금액과 기준 개수가 필요하기 때문에 basePrice와 baseQuantity를 만들어줬습니다.

 

이럴경우 되게 코드가 지저분해보이며 모델도 추가해줘야하고 프로세스도 수정해야하는 여러군데에서 수정이 필요합니다. 또 할인 유형이 생기는 경우 더 늘어나게 됩니다.

 

객체지향의 경우 아래와 같습니다.

// 할인
public class Promotion {
    private Cart cart;
    private DiscountCondition condition;
    
    public void apply(Cart cart) {
    	if (condition.isApplicableTo(cart)){
        	this.cart = cart;
        }
    }
}

// 장바구니
public class Cart {
	private List<CartLineItem> items = new ArrayList<>();

	public Long getTotalPrice() {
		return items.stream().mapToLong(CartLineItem::getPrice).sum();
	}
	public int getTotalQuantity() {
		return items.stream().mapToInt(CartLineItem::getQuantity).sum();
	}
}

// 할인 인터페이스
public interface DiscountCondition {
	boolean isApplicableTo(Cart cart);
}

// 가격 할인 구현체
public class PriceCondition implements DiscountCondition {
    private Long basePrice;
    
    @Override
    public boolean isApplicableTo(Cart cart) {
    	return cart.getTotalPrice() >= basePrice;
    }
}

// 개수 할인 구현체
public class QuantityCondition implements DiscountCondition {
    private int baseQuantity;
    
    @Override
    public boolean isApplicableTo(Cart cart) {
    	return cart.getTotalQuantity() >= baseQuantity;
    }
}

객체지향의 경우 다형성을 이용해야합니다. 그렇기 때문에 interface를 만들어줍니다. Promotion의 apply에서는 interface를 받게끔 해줍니다.

 

파일은 많아집니다만 이런식으로 객체지향식으로 설계가 되어있는 상태에서 다른 할인 유형에 대한 처리가 필요한 경우 DiscountCondition을 상속받아 구현하면 됩니다.

 

Promotion에서 apply는 수정할 필요도 없습니다. DiscountCondition을 상속받은 구현체만 껴주기만 하면 됩니다. 그리고 Promotion을 건들 필요가 없기 때문에 실질적으로 DiscountCondition을 상속받아서 만들어주기만 하면 됩니다. 파일 수정도 한군데에서만 일어나게 됩니다. 이곳저곳 수정할 필요도 없고 DiscountCondition을 무조건 받아야하기 때문에 절차적인 것처럼 임의대로 막 만들수도 없어 개발이 체계적으로 보입니다.

 


위와 같은 상황인 같은 기능을 다른로직으로 갈아껴야하는 상황에는 객체지향이 유리합니다만 무조건적으로 객체지향이 유리하지는 않습니다. 새로운 요구사항을 추가해봅시다. 장바구니에 대한 할인이였는데 이번에는 장바구니에 있는 하나의 상품에 대한 할인 적용을 만들어봅시다. 이번에는 상품인 Item에 대한 모델은 따로 안 만들고 할인에 대한 프로세스에만 집중해봅시다.

 

 

절차지향의 경우 아래와 같습니다.

// 할인 프로세스
public class PromotionProcess {
	public void apply(Promotion promotion, Cart cart) {
		if (isApplicableTo(promotion, cart)) {
			promotion.setCart(cart);
		}
	}

	private boolean isApplicableTo(Promotion promotion, Cart cart) {
		switch (promotion.getConditionType()) {
			case PRICE:
				return cart.getTotalPrice() >= promotion.getBasePrice();
			case QUANTITY:
				return cart.getTotalQuantity() >= promotion.getBaseQuantity();
		}
		return false;
	}

	// 새로 추가된 상품에 대한 할인 적용
	public boolean isApplicableTo(Promotion promotion, CartLineItem item) {
		switch (promotion.getConditionType()) {
			case PRICE:
				return item.getTotalPrice() >= promotion.getBasePrice();
			case QUANTITY:
				return item.getTotalQuantity() >= promotion.getBaseQuantity();
		}
		return false;
	}
}

절차지향의 경우 상품을 매개변수로 받아야 하기 때문에 또 다른 함수를 만듭니다. 다른 파일 건들 필요 없이 간단하게 PromotionProcess에만 추가하면 됩니다.

 

 

객체지향의 경우 아래와 같습니다.

// 할인
public class Promotion {
    private Cart cart;
    private DiscountCondition condition;
    
    public void apply(Cart cart) {
        if (condition.isApplicableTo(cart)) {
            this.cart = cart;
        }
    }
}

// 할인 인터페이스
public interface DiscountCondition {
    boolean isApplicableTo(Cart cart);
    boolean isApplicableTo(CartLineItem item);
}

// Price 할인 구현체
public class PriceCondition implements DiscountCondition {
    private Long basePrice;
    
    @Override
    public boolean isApplicableTo(Cart cart) {
	    return cart.getTotalPrice() >= basePrice;
    }
    
    @Override
    public boolean isApplicableTo(CartLineItem item) {
    	return item.getPrice() >= basePrice;
    }
}

// Quantity 할인 구현체
public class QuantityCondition implements DiscountCondition {
    private int baseQuantity;
    
    @Override
    public boolean isApplicableTo(Cart cart) {
    	return cart.getTotalQuantity() >= baseQuantity;
    }
    
    @Override
    public boolean isApplicableTo(CartLineItem item) {
    	return item.getQuantity() >= basePrice;
    }
}

객체지향의 경우 Interface의 함수를 추가해야하고 이걸 무조건 구현해야하기 때문에 이걸 상속받은 구현체들의 코드는 다 추가되어야합니다. 또한 여기선 Promotion에 코드를 추가 안 했지만 Promotion 코드도 추가해야하기 때문에 총 4개의 파일을 수정해야합니다.

 

 

 


위와 같이 로직이 아예 다른 것을 추가할 때 객체지향의 경우 더 불리합니다. (장바구니할인 → 상품할인) 또 다른 예로는 타입 계층 전체 수정이 있는 경우입니다. Cart와 Promotion 모델을 합쳐서 CartWithPromotion 모델을 만들어야하는 예를 들어봅시다.

 

 

절차지향의 경우 아래와 같습니다.

public class PromotionProcess {

    public CartWithPromotion convertToCartWithPromotion(
	Promotion promotion,
    Cart cart) {
        CartWithPromotion result = new CartWithPromotion();
        result.setTotalPrice(cart.getTotalPrice());
        result.setTotalQuantity(cart.getTotalQuantity());
        result.setPromotionBasePrice(promotion.getBasePrice());
        result.setPromotionBaseQuantity(promotion.getBaseQuantity());
        return result;
    }
}

절차지향의 경우는 되게 간단하게 처리가 가능합니다. 두개의 모델을 받아서 그냥 새로운 모델에 넣어서 반환하면 됩니다.

 

 

 

객체지향의 경우 아래와 같습니다.

public class Promotion {
    private Cart cart;
    private DiscountCondition condition;
    ...
    
    public CartWithPromotion convertToCartWithPromotion() {
        CartWithPromotion result = new CartWithPromotion();
        result.setTotalPrice(cart.getTotalPrice());
        result.setTotalQuantity(cart.getTotalQuantity());
        
        if (condition instanceof PriceCondition) {
            result.setPromotionBasePrice(
            ((PriceCondition)condition).getBasePrice());
        }
        if (condition instanceof QuantityCondition) {
            result.setPromotionBaseQuantity(
            ((QuantityCondition)condition).getBaseQuantity());
        }
    	return result;
    }
}

객체지향의 경우는 되게 복잡하게 처리해야합니다. Interface로 다형성을 유지해야하기 때문에 어떤 구현체가 들어올지 몰라 instanceof를 통해 클래스를 확인한 이후에 각각 다르게 처리해야합니다. 복잡하고 되게 어색합니다.

 


최종적으로 정리해 간단 요약하면 아래 표와 같습니다.

절차적인 설계 객체지향 설계
포맷 변경을 위한 데이터 변환 (데이터 합치기) 규칙에 기반한 상태 변경 (체계적) [복잡한 설계에 유리]
데이터 중심 행동 중심
데이터 노출 데이터 캡슐화
기능 추가에 유리 (아예 새로운 기능 → 장바구니가 아닌 상품 할인 기능이 필요한 경우) 타입 확장에 유리 (본질적인 기능은 같지만 다양하게 확장 가능 → 인터페이스로 인한 할인 확장)
데이터와 프로세스가 명확히 분리 데이터 프로세스 같이 존재 (클래스 안에 할인 관련된 데이터와 할인 프로세스가 같이 들어있다)

 

 

 

  • 도메인 레이어의 경우 객체지향이 좋습니다. (어떤 할인 내용을 적용시킬지 = 할인이라는 공통 분모)
  • 프레젠테이션 레이어의 경우 데이터를 반환하기 때문에 절차지향에 좋습니다.
  • 서비스 레이어의 경우 비즈니스로직순차적 처리가 필요하기 때문에 절차지향에 좋습니다. (서비스에 어떤 할인을 적용시킬지 이런 내용인 인터페이스를 상속받은 구현체가 들어가서 절차지향에 객체지향이 들어간 형태입니다.)
  • 퍼시스턴스 레이어의 경우 DB 쿼리문 조회하고 이런 부분은 순차 처리가 필요하기 때문에 절차지향에 좋습니다. 

 

이미 우리는 상황에 맞게 절차지향과 객체지향을 섞어 쓰고 있습니다. 즉, 우월하다 이런 건 없고 상황에 맞게 잘 써야합니다.

 

 

📝 인터페이스 vs 추상클래스

 

인터페이스

public interface Animal {
    void eat();  // 메서드 선언 (구현 X)
    void sleep();
}

public class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("Dog eats.");
    }

    @Override
    public void sleep() {
        System.out.println("Dog sleeps.");
    }
}

인터페이스의 특징은 아래와 같습니다.

  • 다중 상속 가능
  • 행동의 규약 정의 → 해당 메소드는 반드시 구현해야 함
  • 무엇을 해야하는 가를 정의한다.

 

 

추상클래스

public abstract class Animal {
    private String name;  // 멤버 변수

    public Animal(String name) {
        this.name = name;
    }

    public void breathe() {
        System.out.println(name + " is breathing."); // 일반 메서드
    }

    public abstract void eat();  // 추상 메서드
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void eat() {
        System.out.println("Dog eats.");
    }
}

추상클래스의 특징은 아래와 같습니다.

  • 단일 상속
  • 추상클래스에서 이미 구현되어있기 때문에 상속받아서 직접 구현 안 해도 된다.
  • 기본적인 공통기능에 사용하며 만약 커스텀이 필요한 경우 @overrid로 재정의해서 사용하면 좋다.
  • 공통메서드를 사용하거나 커스텀이 필요한 경우 @override 재정의가 가능하기 때문에 interface처럼 규약에 덜 얽매인다.

 

 

🔗 참고 및 출처

https://www.youtube.com/watch?v=usOfawBrvFY&t=446s

https://cactuslog.tistory.com/

 

 

 

반응형
반응형

📝withCredentials

서로 다른 도메인에 요청을 보낼때 요청에 Credentials 정보를 담아서 보낼지에 대한 여부입니다.

기본적으로 브라우저가 제공하는 요청 API 들은 별도의 옵션 없이 브라우저의 쿠키와 같은 인증과 관련된 데이터를 함부로 요청 데이터에 담지 않도록 되어있다. 이는 응답을 받을때도 마찬가지이다.  따라서 요청과 응답에 쿠키를 허용하고 싶을 경우, 이를 해결하기 위한 옵션이 바로 withCredentials 옵션을 넣어야한다

 

credential 정보가 포함된 요청은 아래와 같습니다.

  1. 쿠키를 첨부해서 보내는 요청
  2. 헤더에 Authorization 항목이 있는 요청

 

📝HttpOnly

자바스크립트로부터 쿠키 접근을 차단하여 XSS 공격 방지를 해준다

 

📝Secure

HTTPS를 통해서만 쿠키를 전송하여 MITM 공격 방지할 수 있다

 

📝SameSite

쿠키가 서로 다른 사이트에서 전송되지 않도록 제한 하는 속성으로 CSRF 공격을 방지하는데 사용됩니다.

 

  • Strict
    • 쿠키가 같은 사이트 내에서만 전송됩니다. 외부 사이트에서 링크 클릭하여 들어오는 경우 쿠키가 전송되지 않습니다.
  • Lax
    • 쿠키가 같은 사이트 내에서만 전송됩니다. 외부 사이트에서 gET 요청이 발생한 경우에는 쿠키가 전송 될 수 있습니다. → 예를 들면 다른 곳에서 쿠팡 링크로 들어왔을 때 어떤 검색어를 통해서 들어왔는지에 대한 쿠키에 대한 정보를 파악하기 위해 필요하다
  • None
    • 쿠키가 모든 사이트 간 전송될 수 있습니다. 이 옵션을 사용할 때는 Secure 속성을 함께 사용해야합니다.

 

 

 

 

 

반응형
반응형

JWT를 이용해 인증, 인가를 구현하는 방법에 대해 설명한다.

 

로그인

  1. 로그인하기
    • 클라이언트에서 아이디, 패스워드 전달
  2. 서버에서 패스워드 암호화 후 DB에서 아이디, 패스워드 검증
  3. 서버에서 Access Token, Refresh Token 토큰 발행
    • Access Secret Key, Refresh Secret Key 각각 다르게 생성
  4. 서버에서 Refresh Token DB 저장
    • 추후 서버에서 강제 로그아웃하기 위해 필요
  5. 서버에서 Response 쿠키에 HttpOnly 사용상태로 리프레시 토큰 저장 후 클라이언트로 보내기
  6. 서버에서 클라이언트로 Access Token 값 보낸후 클라이언트에서 메모리(Redux) 저장

 

권한 필요한 API 통신

일반적으로 토큰은 요청 헤더의 Authorization 필드에 담겨서 보내지게 되는데 JWT에 해당하는 type은 Bearer입니다 → Authorization: <type> <credentials>

Global Guard에 Guards를 적용시키고 필요하지 않은 건 Public Decorator로 Pass하게 한다 (로그인, 회원가입 기능 등…)

Admin만 호출할 수 있는 게 있으면 Role에 담아서 보낸다

  1. 클라이언트에서 요청시 헤더에 Authorization: Bearer ${Access Token}을 붙여서 Access Token과 함께 API 요청을 하고 쿠키의 Refresh Token 내용을 같이 보낸다.
  2. 서버에서 Access Token을 검증하며 정상일 땐 그대로 처리한다 비정상일 땐 Access Token 만료 시나리오대로 진행한다.
  3. Refresh Token이 만료된 경우는 Refresh Token 만료 시나리오대로 한다.

 

권한에 따른 페이지 접근 처리

  1. Jwt의 payload 데이터에 해당 사용자의 역할 정보를 넣어서 암호화 시킨다.
  2. Access Token 발급 받을 때 Header에 Role 정보를 보낸다
  3. Role정보에 따라 페이지를 달리 처리한다
    • Next.js의 경우 admin이라는 라우팅하나 만들고 layout안에 검증식을 넣어놨다

 

Access Token 만료

잘못된 토큰 요청인지 만료되었는지를 클라이언트에게 보여줄 필욘 없기 때문에 유효하지만 않는지 체크만 하면 된다.

  1. 클라이언트에서 서버에 HTTP 요청을 보낸다
    • 모든 요청에는 Access Token은 Bearer에 담아서 보내고 Refresh Token은 쿠키에 담아 보낸다
  2. Access Token가 유효하지 않을 때 쿠키에 담아서 같이 보낸 Refresh Token 값으로 검증 후 정상일 경우 Access Token을 재발급하고 요청한 HTTP통신을 처리하며 Access Token값을 클라이언트에 Response Header로 보낸다
    • 조회 버튼 눌렀는데 발급만 해서 보내면 다시 또 조회버튼을 눌러야하니 사용자가 불편할 수도 있으니 이렇게 처리한다. 또한 HTTPS통신을 사용하면 Response Header값이 암호화 되어서 중간자 탈취에도 안전하다
  3. 클라이언트에서는 Fetcher의 Response에 Access Token키의 값이 왔을 때 Redux에 저장한다

 

Refresh Token 만료

Refresh Token이 만료된 경우 일반적으로 보안상의 이유로 사용자에게 재로그인을 요청하는 것이 일반적인 접근입니다.

재로그인을 통해 새로운 Access Token과 Refresh Token을 발급받는 것이 안전합니다.

  1. 클라이언트에서 Access Token이 만료되었을 때 쿠키에 담아서 보낸 Refresh Token에 대한 검증을 한다. 정상일 경우 Access Token을 재발급하지만 비정상인 경우 다시 로그인 하게끔 해야한다.
  2. 서버에서는 Cookie에 담긴 Refresh Token을 지운다.
  3. HTTPS통신으로 Header에 Refresh Token이 만료 되었다는 값을 담아서 보낸다.
    • HTTPS통신이라 암호화가 되어서 중간 탈취에 안전하다.
  4. 클라이언트는 Fetcher를 통해 Header에 만료되었다는 값이 들어오면 체크해서 Redux에 있는 Access Token을 초기화시키고 Login페이지로 이동시킨다.

 

자동 로그인

  1. 로그인 여부가 true이면 아래 내용 진행 (쿠키 저장을 브라우저 영역으로 저장한다)
  2. 페이지 처음 들어오면 Refresh Token이 존재하는 경우 같이 보낸다
  3. 서버에서 Refresh Token이 정상인 경우 Access Token 만료 시나리오를 따라간
  4. 서버에서 Refresh Token이 비정상인 경우 Refresh Token 만료 시나리오를 따라간다

 

새로고침시 로그인 유효 / 로그인 후 사용 가능한 페이지 접근

  1. 로그인 여부가 true이면 아래 내용 진행 (자동 로그인이 아니면 로그인시 세션 영역으로 만들어짐)
  2. 페이지 처음 들어오면 Refresh Token이 존재하는 경우 같이 보낸다
  3. 서버에서 Refresh Token이 정상인 경우 Access Token 만료 시나리오를 따라간다
  4. 서버에서 Refresh Token이 비정상인 경우 Refresh Token 만료 시나리오를 따라간다

 

 

로그아웃 (버튼)

  1. 서버에서 Refresh Token값이 있는 쿠키를 삭제한다.
  2. 클라이언트에서 메모리에 저장된 Access Token 삭제한다.
  3. 로그인 페이지로 이동시킨다.

 

강제 로그아웃

  1. 클라이언트는 항상 Refresh Token값이 정상인지랑 DB값하고 같은지 체크해야한다
  2. 블랙리스트 방식도 존재하지만 시간이 지나면 쓸모 없는 데이터(어차피 유효기간 지나서 인증 안 되는 JWT 등…)을 주기적으로 삭제해야하는 번거로움이 있기 때문에 선택 안 함
  3. 인메모리를 사용하면 더 효율적이긴하다
  • Token으로 클라이언트에게 주체가 넘어간 경우 서버에서 토큰을 폐기시킬 수 있는 방법은 쿠키로 보낸 Refresh Token값하고 DB에 저장된 Refresh Token값하고 같은지 체크해야한다
  • 로그인시 Redis 같은 인메모리DB에 token 정보를 저장하고, 로그아웃시 Redis에서 token 정보를 지움으로써 로그아웃 여부를 확인할 수 있다

 

소셜로그인

passport.js로 구현한다

  1. passport docs에 있는대로 처리하고 eamil정보를 받아서 따로 회원가입을 진행시키던가 강제로 회원가입 시켜서 회원정보정도는 관리해야한다
  2. 소셜로그인을 클릭한 이후에 동작은 로그인 프로세스와 동일하게 한다
    • 서버에서 Access Token, Refresh Token 토큰 발행
    • 서버에서 Refresh Token DB 저장
    • 서버에서 Response 쿠키에 Http Only 사용상태로 리프레시 토큰 저장 후 클라이언트로 보내기
    • 서버에서 클라이언트로 Access Token 값 보낸후 클라이언트에서 메모리(Redux) 저장

 

Access Token 탈취

  • 메모리에 저장하기 때문에 사용자가 직접 주지 않는 이상 탈취되진 않는다.
  • 기간을 짧게 잡아서 탈취되더라도 못 쓰게한다
  • 메모리에 담기 때문에 XSS나 CSRF 방지가 가능하다
  • HTTPS를 통해 패킷 탈취되어도 암호화가 되어서 안 보이게 된다

 

Refresh Token 탈취

  • 사용자는 리프레시 토큰을 쿠키에 저장해서 보낸다. (Http only, Secure 보안 사항 등록)
  • 리프레시 토큰은 DB에 저장한다
    • JWT 장점은 클라이언트가 인증 권한을 관리해서 서버에서 로그아웃 시킬 수 있는 방법이 없는데 DB나 Redis에 Refresh Token값을 저장하고 Refresh Token 검증시 저장값 하고 다르면 로그아웃시켜버리게 한다

 

XSS 방어로 쿠키 탈취 막기

  • XSS 방어 관련된 라이브러리 (Express의 Helmet 등…)
  • 웹 방화벽
  • Cookie의 Http Only 사용

 

CSRF 막기

  • SameSite설정 → 브라우저 호환 문제 발생으로 사용하기 힘듬
  • 쿠키에 인가 정보 넣지 않기 → 메모리 보관 (Private 변수, Redux)

 

 

🔗 참고 및 출처

https://inpa.tistory.com/entry/AXIOS-📚-CORS-쿠키-전송withCredentials-옵션

https://velog.io/@cada/토근-기반-인증에서-bearer는-무엇일까

https://velog.io/@hahan/JWT란-무엇인가

https://sokdak-sokdak.tistory.com/11

반응형
반응형

📝평문 저장

  • 비밀번호를 그대로 저장
  • 구현이 간단하지만 보안에 매우 취약하다

 

📝단순 해싱

  • 해시 함수를 이용해 해시값으로 변환하여 저장
  • 평문에 비해 보안이 향상되지만 무차별 대입 공격에 취약하며 동일한 비밀번호가 동일 해시값을 가짐으로 레인보우 테이블 공격에 취약하다

 

📝솔팅

  • 비밀번호에 무작위 값(Salt)을 추가한 후 해시 함수로 변환
  • 동일 비밀번호도 서로 다른 해시 값을 가져 레인보우 테이블 공격 방지 가능하지만 빠른 해시 함수는 무차별 대입 공격에 취약하다

 

📝키 스트레칭

  • 비밀번호에 무작위 값을 추가한 이후 해시 함수를 여러번 실행시킨다
  • 주로 CPU 사용량을 증가시켜 해시 계산 속도를 늦추는 데 중점을 둡니다
  • 최근 일반적 장비로는 1초에 50억개 이상의 해시값을 비교할 수 있지만 스트레칭을 적용하면 장비에서 1초에 5번정도만 비교가 가능하다. 즉, 무차별 대입 공격에 강하지만 나도 저장해야하기 때문에 서버에 부담이 된다.
    • PBKDF2 (Password-Based Key Derivation Function 2)
      • 비밀번호와 솔트를 결합한 후 여러 번 반복하여 해시 값을 생성합니다.
    • bcrypt
      • 키 스트레칭을 구현하며, 비교적 느리게 설계되어 공격자가 비밀번호를 추측하는 속도를 늦춥니다.

📝메모리 집약적 함수

  • 메모리 집약적 함수는 해시 계산 과정에서 많은 메모리 및 CPU를 사용하도록 설계되어, 하드웨어 가속 공격에 대한 저항력을 높입니다.
    • Argon2
      • 비밀번호 해시를 생성하는 최신 알고리즘으로, 메모리와 연산 시간을 조절할 수 있으며, 다양한 공격에 대해 강력한 보안을 제공합니다.
    • scrypt
      • bcrypt와 유사하지만, 메모리 사용량을 증가시켜 더욱 강력한 보안을 제공합니다.

 

반응형
반응형

📝OAuth 2.0이란

Authentication 사용자의 인증입니다
Authorization 사용자의 인가로 어떤 자원에 접근할 권한을 부여하는 것입니다
Access Token 리소스 서버에게서 리소스 소유자의 보호된 자원을 획득할 때 사용되는 만료 기간이 있는 Token입니다
Refresh Token Access Token 만료시 이를 갱신하기 위한 용도로 사용하는 Token입니다

 

📝OAuth 2.0의 4가지 역할

Resource Owner 사용자입니다.
Client 보호된 자원을 사용하려고 접근 요청을 하는 애플리케이션입니다.
예) 쇼핑몰 홈페이지
Resource Server 사용자의 보호된 자원을 호스팅하는 서버입니다.
예) 구글 사용자 정보 관리 서버
Authorization Server 권한 서버. 인증/인가를 수행하는 서버로 클라이언트의 접근 자격을 확인하고 Access Token을 발급하여 권한을 부여하는 역할을 수행합니다.
예) 사용자 서버

 

 

📝 OAuth 2.0 추가 및 보완된 기능

  • 1.0에 비해 구현이 쉬워졌습니다
  • 웹, 앱 데스크톱 등 다양한 환경에서 지원이 가능해집낟
  • 리프레시 토큰 개념이 추가 되었습니다
  • HTTPS를 통해 암호화를 강화시켰습니다

 

 

📝 OAuth 2.0 프로토콜

Authorization Code Grant

가장 많이 사용하고 기본이 되는 방식입니다. 로그인한 이후에 권한 부여 승인 코드를 전달 받습니다. 해당 코드는 일회용이며 해당 코드로 Access Token을 요청한 이후에 받아서 원하는 자원에 접근하게끔 사용합니다.

 

 

Implicit Grant 

권한 부여 승인 코드 없이 바로 Access Token을 발급합니다. 비교적 간소화 되기 때문에 빠른 응답이 있지만 Refresh Token이 사용 불가능하며(?) 안전하게 저장하기 힘든 클라이언트(JS 사용 브라우저)에 최적화된 방식입니다. → 서버가 없다는 거 자체가 이해가 안 된다.

 

Resource Owner Password Credentials Grant

username, password를 전달해 Access Token을 받습니다. 또한 Refresh Token이 사용이 가능합니다. 이 방식은 권한서버, 리소스 서버, 클라이언트가 모두 같은 시스템에 속해 있을 때 사용되어야하는 방식입니다. → Third Part를 사용 안 하고 내가 직접 인증서버를 관리할 때를 의미하는 거 같다

 

Client Credentials Grant

검증된 클라이언트 서버(예를 들면 쇼핑몰 웹서버)에서 자기는 안전하다고 판단한 경우에 사용됩니다. 이 경우에는 Resource Server는 사용자의 정보가 들어있는 곳보다는 모든 로그가 쌓여있고 필터링이 따로 필요 없는 서버를 접근하기 위한 것이고 이미 요청한 서버는 안전하다고 판단하기 때문에 Access Token을 요청하면 바로 해당 서버의 Acces Token을 바로 발급해주는 것입니다. Refresh Token은 사용할 수 없습니다.

 

📝 OIDC (Open ID Connect)

OAuth 2.0의 확장으로 Access Token으로 접근권한 뿐만 아니라 사용자 정보도 ID토큰으로 받아와 사용할 수 있습니다.

 

📝 개인적인 생각

위 프로토콜들이 이해가 안 되는게 많다 일단 로그인 처리가 되고 난 이후에 권한 부여 승인 코드를 따로 받는 것 그 이후에 그걸 가지고 Access Token을 굳이 또 요청해야하는 작업이 필요한 것일까? 로그인이 완료 되었으면 다 된 거 같은데 또한 Refresh Token을 못 쓴다는데 Refresh Token을 Access Token하고 같이 주면 되는 거 아닌가 싶다

 

 

🔗 참고 및 출처

https://blog.naver.com/mds_datasecurity/222182943542

반응형
반응형

📝Failover

"장애 극복 기능"이란 뜻으로 시스템 장애 시 준비되어있는 다른 시스템으로 대체되어 운영되는 것을 의미한다

 

📝CDC (Change Data Capture)

DB 변경 사항을 실시간으로 감지하고 이를 다른 시스템으로 전송하는 기술로 데이터 통합, 복제, 실시간 분석 및 이벤트 스트리밍 등에 사용됩니다.

 

📝ETL (Extract, Transform, Load)

데이터베이스, 파일 시스템, API 등 다양한 소스에서 데이터를 추출(Extract)하고, 이를 원하는 형태로 변환(Transform)한 다음, 데이터 웨어하우스, 데이터 레이크, 데이터베이스 등의 대상 시스템에 적재(Load)하는 프로세스입니다. Apache Spark, Google Cloud Dataflow 등이 있다.

 

📝Throughput

시스템이나 네트워크가 주어진 시간 동안 처리할 수 있는 데이터의 양을 나타내는 성능 지표입니다.

 

📝페이지 캐시 (Page Cache)

운영 체제(OS)가 디스크로부터 데이터를 읽어올 때 사용되는 메모리 내의 캐시입니다. 디스크 I/O 성능을 향상시키기 위해 사용되며, 자주 접근하는 데이터를 메모리에 캐시하여 디스크 접근을 최소화합니다

 

 

🔗 참고 및 출처

https://habitus92.tistory.com/16

반응형
반응형

📝고가용성 (高可用性, HA : High Availability)

서버와 네트워크 또는 프로그램 등의 정보 시스템이 상당히 오랜 기간 동안 지속적으로 장애 없이 정상 운영이 가능한 성질

 

📝온프레미스

소프트웨어나 하드웨어를 클라우드 서비스가 아닌 자체 데이터 센터나 서버에서 직접 운영하는 방식을 의미

 

📝거버넌스

기업의 IT 자산, 데이터, 프로세스를 관리하고 통제하는 체계를 의미합니다

 

📝데이터 파편화

데이터가 여러 위치에 분산되어 저장되어 있는 상태를 의미합니다. 이는 데이터 일관성, 관리, 검색의 어려움을 초래 할 수 있으며, 데이터를 통합하여 분석하는 데 어려움을 줄 수 있습니다.

 

📝Materialized View

물리화된 뷰는 데이터베이스에서 사용되는 개념으로, 쿼리 결과를 미리 계산하여 물리적으로 저장해 둔 테이블입니다. 이는 복잡한 쿼리 성능을 향상시키기 위해 사용되며, 주기적으로 또는 수동으로 갱신될 수 있습니다.

이름이 저런 거지 따로 저런 View가 존재하는 게 아니다 즉, 테이블인데 쿼리 결과를 미리 계산해서 물리적으로 저장해둔 테이블이라는 것이다

 

📝티어드 스토리지 (Tiered Storage)

티어드 스토리지는 데이터의 중요도나 사용 빈도에 따라 서로 다른 성능과 비용을 가진 스토리지 계층에 데이터를 배치하는 전략입니다. 자주 사용되는 데이터는 고속의 고비용 스토리지에 저장하고, 덜 사용되는 데이터는 저속의 저비용 스토리지에 저장합니다.

 

📝카프카 미러메이커

카프카 미러메이커는 Apache Kafka에서 제공하는 데이터 복제 도구입니다. 이는 하나의 Kafka 클러스터에서 다른 클러스터로 데이터를 실시간으로 복제하여 데이터의 가용성을 높이고, 여러 데이터 센터 간의 데이터 동기화를 가능하게 합니다.

 

📝멱등성

수학과 컴퓨터 과학에서 중요한 개념으로, 연산을 여러 번 적용해도 결과가 달라지지 않는 성질을 의미합니다

반응형