반응형

https://school.programmers.co.kr/learn/courses/30/lessons/131123

p131123 Level.3 GROUP BY

내가 시도한 방식

SELECT FOOD_TYPE, REST_ID, REST_NAME, MAX(FAVORITES)
FROM REST_INFO
GROUP BY FOOD_TYPE
ORDER BY FOOD_TYPE DESC;

정답

SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
FROM REST_INFO
WHERE (FOOD_TYPE, FAVORITES) IN 
       (SELECT FOOD_TYPE, MAX(FAVORITES)
        FROM REST_INFO
        GROUP BY FOOD_TYPE)
ORDER BY FOOD_TYPE DESC

서브쿼리를 넣어야 하는 이유 : 두 컬럼의 조건이 일치해야 한다

처음 넣었던 MAX함수만으로 뽑게되면 식당 명과 일치하지 않게 되는 문제가 발생한다.

반응형
반응형

애플리케이션 수준 보안을 지원하는 스프링 시큐리티

스프링 시큐리티는 인프라적으로 가장 최상층에 위치한 애플리케이션 수준 보안을 구현한다

웹 애플리케이션의 일반적인 보안 취약성

  • 인증 취약성
  • 세션 고정
  • XSS(교차 사이트 스크립팅)
  • CSRF(사이트 간 요청 위조)
  • 주입
  • 기밀 데이터 노출
  • 메서드 접근 제어 부족
  • 알려진 취약성이 있는 종속성 이용

인증과 권한 부여의 취약성

  • 인증(Authentication)
    • 애플리케이션을 이용하려는 사람을 식별하는 프로세스
    • 사용자의 ID를 확인하고 나면 권한을 부여하는 프로세스가 시작
  • 권한 부여(Authorization)
    • 인증된 호출자가 특정 기능과 데이터에 대한 이용 권리가 있는지 확인하는 프로세스
    • ex) 대부분의 인증된 사용자는 본인의 계좌에서만 이체가 가능하다
  • 세션 고정(Session fixation)
    • 웹 애플리케이션의 더 구체적이고 심각한 약점
    • 이미 생성된 세션 ID를 재이용해 유효한 사용자를 가장할 수 있다.
    • 취약성 발생이유 : 인증 프로세스 중 고유한 세션ID를 할장하지 않아 기존 세션ID가 재사용될 가능성이 있을 때 발생
    • 공격방식 : 세션ID가 URL에 들어있는 방식으로 세션이 구현되어있을 때 악성 링크를 클릭하도록 유인할 수 있다. 이 때 클릭했을 때 세션 ID가 탈취된다.
      세션 값을 쿠키에 저장하는 경우 피해자의 브라우저가 스크립트를 실행하도록 할 수도 있다.
  • XSS(교차 사이트 스크립팅, Cross Site Scripting)
    • 클라이언트 쪽 스크립트를 주입해 다른 사용자가 이를 실행하도록 한다.
    • 소독 하는 과정을 통해 해결
    • 이 취약성으로 인해 발생되는 문제 : 계정 가장(세션 고정과 결합), DDOS
  • CSRF(사이트 간 요청 위조, Cross-Site Request Forger)
    • 서버가 요청의 출처를 확인하지 않을 때 발생하는 문제(모든 곳에서 요청이 실행될 수 있음)
    • 일반적으로 공격자는 CSRF를 이용해 시스템의 데이터를 변경하는 동작을 실행
  • 웹 애플리케이션의 주입(Injection) 취약성 이해
    • 주입 공격은 광범위한 공격 방식.
    • 공격자는 시스템에 특정 데이터를 주입하는 취약성을 이용
    • 공격의 목표 : 시스템의 데이터 변경, 삭제, 무단 이용을 유발
    • 주입 공격의 유형 : XSS Injection, SQL Injection, XPath Injection, OS Command Injection, LDAP Injection 등
  • 민감한 데이터의 노출 처리하기
    • 공개정보가 아닌 것은 절대 로그에 기록하지 말아야 한다
    • 로그에 기록하지 말아야 하는 예시
      • [오류] 요청의 서명이 잘못되었습니다. 사용할 올바른 키는 X입니다.
      • [경고] 사용자 이름 X와 암호 Y를 이용하여 로그인하지 못했습니다.
      • [정보] 사용자 X가 올바른 암호 Y를 이용하여 로그인했습니다.
    • 애플리케이션에 예외가 발생했을 때 서버가 클라이언트에 반환하는 정보를 주의
    • 로그인의 예시
      • 사용자의 이름이 올바르지 않음, 사용자의 암호가 올바르지 않음
        보다 사용자 이름 또는 암호가 올바르지 않음을 통해 처리하는 것이 정보를 제공하지 않기에 더 바람직함
  • 메서드 접근 제어 부족
    • 컨트롤러 단에서 구성했을 때 나중에 다른 컨트롤러에서 레포지토리 참조시 권한부여가 제대로 안될 수도 있다.
  • 알려진 취약성이 있는 종속성 이용
    • 개발하는 애플리케이션이 아닌 기능을 만들기 위해 이용하는 라이브러리나 프레임워크 같은 종속성에 취약성이 있을 수 있다.
    • 메이븐 또는 그레이들 구성에 플러그인을 추가하면 정적 분석을 수행할 수 있음

OAuth 2 흐름 이해

인증 권한 부여 방식

  • 사용자가 애플리케이션접근 시 백엔드 리소스 호출
  • 권한 부여 서버를 호출해서 토큰을 획득, 자격증명, 갱신 토큰으로 토큰 획득
  • 자격 증명, 갱신 토큰이 올바를 때 새로운 액세스 토큰을 클라이언트로 반환
  • 리소스 호출 시 서버에 요청할 때 헤더에 액세스 토큰을 담아 서비스 이용

토큰 형태로 애플리케이션이 구현되었을 때 이점

  • 클라이언트는 사용자 자격 증명을 저장할 필요 없이 액세스 토큰과 갱신 토큰만 저장하면 된다.
  • 애플리케이션은 사용자 자격 증명을 노출하지 않는다.
  • 토큰을 가로챘을 때 사용자 자격 토큰을 실격시킬 수 있다.
  • 토큰을 사용했을 때는 제삼자가 사용자를 가장하지 않고도 사용자 대신 리소스에 접근할 수 있다. 토큰의 수명은 짧기에 취약성을 악용할 기한이 제한된다.

API 키, 암호화 서명, IP 검증을 이용해 요청 보안

교환되는 메시지를 아무도 변경하지 못하게 하기 위해 백엔드 구성요소간 보안을 거는 방식이 있다.

  • 요청 및 응답 헤더에 정적 키 이용
  • 암호화 서명으로 요청 및 응답 서명
  • IP 주소에 검증 적용

통신의 신뢰성을 테스트하는 제일 좋은 방법은 암호화 서명을 이용하는 것

이 책에서 배울 내용

스프링 시큐리티를 배우는 실용적 접근법 소개

  • 스프링 시큐리티의 아키텍처와 기본 구성 요소 및 이를 이용해 애플리케이션을 보호하는 방법
  • OAuth 2 및 OpenID Connect 흐름과 시큐리티로 인증과 권한 부여를 구현하는 방법
  • 애플리케이션의 다양한 계층에서 스프링 시큐리티로 보안을 구현하는 방법
  • 다양한 구성 스타일과 프로젝트에 맞는 모범 사례
  • 리액티브 애플리케이션에 스프링 시큐리티 이용
  • 보안 구현 테스트

요약

  • 스프링 시큐리티는 스프링 애플리케이션을 보호하기 위한 가장 인기 있는 선택이며 다양한 스타일과 아키텍처에 적용할 수 있는 갖가지 대안을 제공한다
  • 시스템의 계층별로 보안을 적용해야 하며 계층별로 다른 관행을 이용해야 한다.
  • 보안은 소프트웨어 프로젝트를 시작할 때부터 고려해야 하는 공통 관심사다
  • 일반적으로 취약성을 예방하는 투자 비용보다 공격의 대가가 훨씬 크다.
  • 오픈 웹 애플리케이션 보안 프로젝트(OWASP)는 취약성과 보안 관련 사항을 참고할 수 있는 훌륭한 장소다.
  • 종종 아주 작은 실수 때문에 큰 피해가 발생한다.( 로그나 오류 메시지에 민감한 데이터 노출)
반응형
반응형

Chapter01 객체, 설계

step01. 구현

  • 수동적이지 않은 객체
    • 객체의 메서드가 모두 열려있음 - public
    • 하나의 객체(Theater)가 모든 것을 조종함 - Processing(절차지향적)
  • 변경에 취약한 코드
    • 요구사항이 변경 될 가능성
    • 구현된 클래스가 다른 클래스에 의존되어 구현된다.
    • 결합도(coupling)가 높음
public class Theater {
    private TicketSeller ticketSeller;

    public Theater(TicketSeller ticketSeller) {
        this.ticketSeller = ticketSeller;
    }

public void enter(Audience audience) {
        if (audience.getBag().hasInvitation()) {
            Ticket ticket = ticketSeller.getTicketOffice().getTicket();
            audience.getBag().setTicket(ticket);
        } else {
            Ticket ticket = ticketSeller.getTicketOffice().getTicket();
            audience.getBag().minusAmount(ticket.getFee());
            ticketSeller.getTicketOffice().plusAmount(ticket.getFee());
            audience.getBag().setTicket(ticket);
        }
    }
}

Step02. 설계 개선

  • 자율적인 존재로 만들기
    • 기존 : 티켓 판매를 티켓 판매원이 아닌 Theater가 담당함
    • 변경 : 티켓 판매 로직을 티켓 판매원에게 양도
    • TicketSeller{ ... public void sellTo(Audience audience){ if(audienct.getBag().hasInvitation()){ Ticket ticket = ticketOffice.getTicket(); audience.getBag().setTicket(ticket); }else{ Ticket ticket = ticketOffice.getTicket(); audience.getBag().minusAmount(ticket.getFee()); ticketOffice.plusAmount(ticket.getFee90); audience.getBag().setTicket(ticket); } } ... } -> public class Theater { ... public void enter(Audience audience){ ticketSeller.sellTo(audience); } ... }
  • 기존 : bag을 getter로 불러옴
  • 변경 : bag을 private화 + getter삭제 + 공용 인터페이스인 buy()를 bag에 선언
  • public class Audience{ public Bag bag; -> private Bag bag; public Bag getBag() { return bag; } -> public Long buy(Ticket ticket){ if( bag.hasInvitation()) { bag.setTicket(ticket); return 0L; } else { bag.setTicket(ticket); bag.minusAmount(ticket.getFee()); return ticket.getFee(); } }
  • 변화점 : 각 객체들이 맡은 책임에 맞게 일을 행하도록 구현되었다.
  • Theater의 경우를 예로 들었을 때 객체는 다른 객체에게 이 일을 행해달라고 전달했을 뿐이다.

캡슐화와 응집도

  • 객체지향의 핵심은 객체 내부의 상태를 캡슐화하고 객체 간에 오직 공용 인터페이스(메시지)를 통해서만 상호작용하도록 만드는 것
  • 객체가 밀접하게 연관된 작업만을 수행하고 연관성이 없는 작업은 다른 객체에게 위임하는 것이 응집도를 높이는 방법이다.
  • 자신의 데이터를 책임지며 자신의 데이터를 가공하는 것이 객체의 응집도를 높이는 핵심

절차지향과 객체지향

  • 절차적 프로그래밍
    Step01에서는 Theater가 절차지향적인 코드였으며, Process역할을 했었다. 이렇게 Step01의 Theater처럼 별도 모듈에 위치시키는 방식
  • 객체지향 프로그래밍
    Step02에서는 프로세스가 각 객체 안에서 동작하도록 구성했다. ex)class Audience
  • 책임의 이동(shift of responsibility)
    두 방식의 근본적인 차이는 기능을 처리할 때 Theater가 직접 처리를 하는 방식과, Theater가 말을하면 Audience와 TicketSeller가 스스로 처리를 하는 방식으로 구분을 할 수 있다.
    • 책임 집중 : Theater
    • 책임 분산 : buy → Audience, SellTo → TicketSeller

Step03. 추가 개선

TicketOffice

  • 기존 : getTicket, getFee를 통해 티켓 자체를 Office에서 꺼내옴
  • 변경 : sellTicketTo를 통해 기존의 티켓을 꺼내오는 방식 변경
  • class TicketOffice{ ... public Ticket getTicket(){ ... } public void plusAmount(){ ... } ... } -> class TicketOffice{ ... public void sellTicketTo(Audience audience){ plusAmount(audience.buy(getTicket())); } private Ticket getTicket(){ ... } private void plusAmount(){ ... } ... } public TicketOffice getTicketOffice() { return ticketOffice; } -> public class TicketSeller{ public void sellTo(Audience audience){ ticketOffice.sellTicketTo(audience); } }
  • 인터페이스에만 의존하게하는 형태로 변경됨
  • but TicketSeller는 audience를 넘겨주며 서로 의존하게 만듦

트레이드오프

  • 인터페이스에만 의존하는 Audience결합도가 중요한지, audience를 넘겨주며 의존성이 생겨난 것이 더 좋을지 개발자는 트레이드 오프를 해야 할 순간이 온다.
  • 두가지 이슈를 통해 (책에서의)개발팀은 TicketOffice의 자율성을 지켜 의존성 제거를 택했다.

의인화

Theater, Bag, TicketOffice는 실세계에서 자율적인 존재가 아니다. 하지만 객체지향 패러다임에서는 생물과 동일하게 객체로 다뤘다. 이렇게 모든 객체는 능동적이고 자율적인 존재로 바뀌도록 설계하는 원칙을 의인화라고 부른다

설계

설계란 코드를 배치하는 것이다 - Metz12 -

  • 요구사항은 항상 변경된다. → 코드는 항상 변경된다.
  • 설계는 코드를 잘 배치하는 것 → 변경될 때 코드의 변경을 최소화하는 것
  • 코드의 변경을 최소화하려면 → 객체 사이의 의존성을 적절하게 관리하는 것
반응형

+ Recent posts