Skip to content

김현욱 4주차 학습일지

김현욱 edited this page Jul 22, 2024 · 3 revisions

Bean 생성 및 관리

서버에서 매번 요청이 들어올때마다 서비스 객체 혹은 handler 객체를 생성하게 된다면?

-> 100개의 요청이 들어오면 100개의 동일한 handler 객체가 생성되기 때문에 메모리 낭비다.

따라서 싱글톤으로 관리한 뒤 단 한개만의 readonly 객체를 공유할 수 있도록 해야한다 -> 하지만 싱글톤으로 작성하게 된다면 객체간의 강한 결합도가 생기게 되어 확장에 어려움이 있다. -> 강한 결합으로 인해 테스트코드를 작성할 때 컨트롤하지 못하는 부분에 대해서 모킹하기 어렵다

DI & IOC 기법

  • 싱글톤패턴을 노출시키는것이 아닌, 객체간 추상화된 인터페이스에 의존하여 외부에서 주입받는 기법을 의미한다.
  • 추상화된 인터페이스에 의존하므로 확장 및 유지보수에 용이한 구조가 된다.
  • 또한, 외부에서 주입하기 때문에 객체 내부에는 어떤 클래스인지 구체적인 정보를 알 필요가 없다. -> 다형성을 쉽게 이용할 수 있으며 다른 객체의 변화에 영향을 받지 않는다.

DI컨테이너

외부 클래스( 본인은 Main 클래스가 DI컨테이너 역할을 했습니다 ) 에서 객체를 생성 및 의존관계를 주입하게 되면 코드의 유지보수에 어려움이 생긴다.

아래는 기존 컨테이너 역할을 맡은 Main의 클래스이다.

public class Main {
    private final static Logger logger = LoggerFactory.getLogger(Main.class);

    private HttpHeaderParser headerParser() {
        return new HttpHeaderParser();
    }

    private HttpBodyParser bodyParser() {
        return new HttpBodyParser();
    }

    private HttpQueryStringParser queryStringParser() {
        return new HttpQueryStringParser();
    }

    private HttpRequestStartLineParser startLineParser() {
        return new HttpRequestStartLineParser();
    }

    private SessionStorage sessionStorage(){
        return new SessionStorage();
    }
    private SessionManager sessionManager() {
        return new SessionManager(sessionStorage(),timer());
    }

    private RequestParser requestParser(HttpRequestStartLineParser startLineParser,
                                            HttpQueryStringParser queryStringParser,
                                            HttpHeaderParser headerParser,
                                            HttpBodyParser bodyParser,
                                        SessionManager sessionManager) {
        return new HttpRequestParser(startLineParser, headerParser, bodyParser, queryStringParser, sessionManager);
    }

    private Timer timer() {
        return new SystemTimer();
    }

    private ExecutorService executorService() {
        return new ThreadPoolExecutor(10, 100, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    }

    private RequestHandlerMapper requestHandlerMapper() {
        return new RequestHandlerMapperImpl();
    }

    private DateFormat dateFormat(){
        DateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        return format;
    }

    private Server server(int port) throws IOException {
        return new Server(port,
                timer(),
                executorService(),
                requestParser(startLineParser(), queryStringParser(), headerParser(), bodyParser(),sessionManager()),
                requestHandlerMapper(),
                dateFormat());
    }
....

DI container 도입으로 원하는 컴포넌트에 @Coffee, 생성자 주입을 받을곳에 @Barista 를 붙이면 직접 주입하지 않아도 DI컨테이너가 주입해주기 때문에 컴포넌트가 늘어나더라도 유지보수가 용이해졌습니다.

@Coffee
public class SessionManager {
    private final Timer timer;
    private final SessionStorage sessionStorage;
    @Barista
    public SessionManager(SessionStorage sessionStorage,Timer timer) {
        this.sessionStorage = sessionStorage;
        this.timer = timer;
    }

    public Optional<Session> getSession(String sessionId){
        return sessionStorage.get(sessionId)
                .filter(session->!session.isExpired()&&timer.getCurrentTime().before(new Date(session.getCreatedAt().getTime()+session.getMaxInactiveInterval()*1000)))
                .map(session->{
                    session.setLastAccessedAt(timer.getCurrentTime());
                    return session;
                });
    }

    public Session createSession(){
        String id = generateSessionId();
        Session session = new Session(timer.getCurrentTime(),timer.getCurrentTime());
        session.setId(id);
        sessionStorage.add(id,session);
        return session;
    }

    private String generateSessionId(){
        return UUID.randomUUID().toString();
    }

}

Password Encrypt

사용자의 비밀번호를 DB에 그대로 저장한다면?

백도어 공격 및 DB 접근 권한만 취득할 수 있다면 사용자의 비밀번호를 모두 열람할 수 있다.

암/복호화는?

사용자의 비밀번호를 암호화 복호화하게된다면 열람하더라도 원래의 비밀번호를 알 수는 없지만, 비밀키가 유출된다면 원래의 비밀번호를 유추할 수 있게된다.

해싱

단방향 암호화를 하게된다면, DB에서 열람을 하더라도 원래의 비밀번호를 알지 못하고, 키가 없기때문에 알 수 없게된다. 따라서 해싱기법을 이용하여 비밀번호를 저장하고, 매칭하여 로그인 및 회원가입을 진행한다.

Rainbow Table

해싱한 문자열에서 원래 문자열을 찾으려면 매우 많은 경우의수를 대입해보며 비교해야한다. 하지만 이런 모든 경우의수를 구해놓은뒤 저장한 레인보우 테이블 에 해싱된 문자열을 입력하게 된다면 원래의 문자열을 추론할 수 있다.

Salt기법

소금을 음식에 뿌려 조리하듯, 원래의 문자열에 랜덤한 문자열(Salt)을 조합하여 해싱하는 기법을 의미한다.

이는, 레인보우 테이블에 의해 원래의 문자열을 유추당하더라도, Salt가 섞인 문자열이 유추되기때문에 원래의 비밀번호를 유추하기 힘들다.

XSS(Cross Site Script) 공격

요청에 악성 script태그를 넣어 서버 및 사용자를 공격하는 기법을 의미한다.

  1. Stored xss 영속되는 데이터에 script 태그를 넣은 뒤, 해당 데이터를 조회하는 사람에게 악성 script태그를 실행시키는 기법을 의미한다.

  2. reflected xss 공격자가 입력한 즉시 script 태그가 실행되는 기법이다. 공격자의 입력 값이 HTTP 요청을 통해 그대로 사용자에게 반사되어 보인다.

  3. Dom xss 공격자가 공격 스크립트가 담긴 DOM을 작성 또는 수정한 후 다른 사용자가 해당 페이지를 열어보게 하여 실행되는 공격이다

방어하는 방법

HTML에서 태그로 인식되는 문자들을 HTML Entity로 변환하여 사용자에게 제공한다. 사용자는 HTML Entity가 괄호 혹은 태그로 보이겠지만, 렌더링을 할 때 태그로 인식되지 않기 때문에 실행되지 않는다.

👼 개인 활동을 기록합시다.

개인 활동 페이지

🧑‍🧑‍🧒‍🧒 그룹 활동을 기록합시다.

그룹 활동 페이지

🎤 미니 세미나

미니 세미나

🤔 기술 블로그 활동

기술 블로그 활동

📚 도서를 추천해주세요

추천 도서 목록

🎸 기타

기타 유용한 학습 링크

Clone this wiki locally