[Spring Boot] 스프링부트 원리 - 내장 서버 (HTTPS와 HTTP2), 요약

dsunni·2020년 7월 30일
2

참고

https://opentutorials.org/course/228/4894


HTTPS vs HTTP

HTTP(Hypertext Transfer Protocol)은 Hypertext인 HTML을 전송하기 위한 통신 규약을 의미한다.

HTTP는 암호화되지 않은 방법으로 데이터를 전송하기 때문에 주고받는 메시지를 변조시키거나 가로채는 것이 쉽다. 따라서 보안성이 향상된 HTTP인 HTTPS가 탄생했다.

HTTPS의 S는 Over Secure Socket Layer의 약자로 보안이 강화된 HTTP를 말한다.


HTTPS와 SSL

HTTPS와 SSL은 동일한 의미로 쓰이기도 한다. 이는 인터넷과 웹의 관계와 비슷하다. 웹이 인터넷 위에서 돌아가듯이 HTTPS는 SSL 프로토콜 위에서 돌아가는 프로토콜이다.


1. HTTPS 사용하기

(1) keystore 생성하기

HTTPS (SSL)을 사용하려면 keystore(인증서)를 만들어야한다

터미널에 다음과 같이 입력하면 keystore가 생성된다

$ keytool -genkey -alias spring -storetype PKCS12 -keyalg RSA -key$ keytool -genkey -alias spring -storetype PKCS12 -keyalg RSA -key
size 2048 -keystore keystor
e.p12 -validity 4000
Enter keystore password:
Re-enter new password:
What is your first and last name?
  [Unknown]:  DSUNNI
What is the name of your organizational unit?
  [Unknown]:  dsunni
What is the name of your organization?
  [Unknown]:  CEO
What is the name of your City or Locality?
  [Unknown]:  Seoul
What is the name of your State or Province?
  [Unknown]:  Seoul
What is the two-letter country code for this unit?
  [Unknown]:  WA
Is CN=DSUNNI, OU=dsunni, O=CEO, L=Seoul, ST=Seoul, C=WA correct?
  [no]:  yes

image

위와같이 keystore가 생성된 것을 확인할 수 있다.


application.properties

server.ssl.key-store=keystore.p12
server.key-store-stype=PKCS12
server.ssl.key-store-password=123456
server.ssl.key-alias=spring
  • server.ssl.key-store=keystore.p12
    • keystore가 root에 생긴다.
    • keystore를 classpath에 넣고 싶으면 다음과 같이 classpath:를 추가해주면 된다.
      • server.ssl.key-store=classpath:keystore.p12

(2) 실행해보기

Spring Boot는 기본적으로 Tomcat이 사용하는 Connector를 하나만 등록해준다. 위와 같은 과정을 거치면 그 Connector에 SSL을 적용해준다.

따라서 앞으로 모든 요청은 앞에 https를 붙여야한다.


image

http로 localhost에 접속하면 위와 같은 Bad Request가 뜨는 걸 확인할 수 있다.


image

https로 들어가면 위와 같은 에러 화면이 뜬다.

브라우저가 서버에 요청을 보냈을 때 서버는 브라우저에게 인증서를 같이 보낸다. 그 때 브라우저가 인증서의 pubkey를 모르는 상태이면 위와 같은 에러 화면이 뜬다.

대부분의 공인인증서의 pubkey는 브라우저가 알고 있지만 Local에서 만든 keystore 안의 인증서는 브라우저가 알 수가 없다.


package me.dsunni;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class Application {
    @GetMapping("/hello")
    public String hello() {
        return "Hello dsunni Spring Study :)";
    }
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
  • hello 라는 Controller로 한번 test 해보자

image

https로 들어가면 200으로 data가 return 된는 것을 확인할 수 있다.



2. HTTP, HTTPS 둘 다 받기 (HTTP 커넥터 설정하기)

https://github.com/spring-projects/spring-boot/tree/v2.0.3.RELEASE/spring-boot-samples/spring-boot-sample-tomcat-multi-connectors

(1) 톰캣 Connetor 생성하기

Application.java

package me.dsunni;

import org.apache.catalina.connector.Connector;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class Application {
    @GetMapping("/hello")
    public String hello() {
        return "Hello dsunni Spring Study :)";
    }
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public ServletWebServerFactory serverFactory() {
        TomcatServletWebServerFactory tomcatServletWebServerFactory
                = new TomcatServletWebServerFactory();
        		tomcatServletWebServerFactory.addAdditionalTomcatConnectors(createStandardConnector());

        return tomcatServletWebServerFactory;
    }

    private Connector createStandardConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setPort(8080);

        return connector;
    }
}

새로운 Connector를 추가한 후 그 Connetor의 포트를 8080으로 설정해두면 http로 8080 포트 접속이 가능하다.


(2) 기존 Connector port 설정

application.properties

server.ssl.key-store=keystore.p12
server.key-store-stype=PKCS12
server.ssl.key-store-password=123456
server.ssl.key-alias=spring

server.port=8443

기존 톰캣 Connector의 포트를 8443으로 설정해두면 https로 8443 포트 접속이 가능하다.


(3) curl 테스트

1. 8080 포트 (새로운 Connector)

image

http로 8080 접속이 가능하다


2. 8443 포트 (기존 Connector)

image

https로 8443 접속이 가능하다



3. HTTP2

참고

https://medium.com/@shlee1353/http1-1-vs-http2-0-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EA%B0%84%EB%8B%A8%ED%9E%88-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0-5727b7499b78


HTTP와 HTTP2

Image for post

HTTP1은 기본적으로 Connection당 하나의 요청을 처리하기 때문에 동시 전송이 불가능하고 요청과 응답이 순차적으로 이루어진다.

이렇다 보니, HOL(Head Of Line) Blocking-특정응답지연, RTT(Round Trip TIme) 증가, 헤비한 Header구조라는 문제점들을 갖고잇다.

HTTP2는 HTTP1에 비해 성능뿐 아니라 속도 면에서도 월등하다.

  • Multiplexed Streams : 한 커넥션에 여러개의 메세지를 동시에 주고 받을 수 있음
  • Stream Prioritization : 요청 리소스간 의존관계를 설정
  • Server Push : HTML문서상에 필요한 리소스를 클라이언트 요청없이 보내줄 수 있음
  • Header Compression : Header 정보를 HPACK압충방식을 이용하여 압축전송

application.properties

server.http2.enabled=true

위와 같이 추가하면 HTTP2 사용이 가능하다.

하지만 서버마다 제약사항이 다 다르다. undertow는 HTTPS만 적용되어있으면 어떠한 추가 설정이 없어도 HTTP2 사용이 가능하다.

image


반면 Tomcat은 매~우 복잡하다. (Tomcat 8 기준)

Tomcat 9, JDK 9는 추가적인 설치 없이 가능하다.

pom.xml

<properties>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.9</java.version>
    <tomcat.version>9.0.10</tomcat.version>
</properties>

<properties>를 추가해주면 java version과 tomcat version을 변경할 수 있다.



독립적으로 실행 가능한 JAR

mvn package 를 하면 실행 가능한 JAR 파일이 하나 생성된다.

Spring Boot는 내장 jar라고 해서 jar안에 의존성인 모든 jar들을 묶어둔다. 그리고 이것들을 읽을 수 있는 파일(JarFile.class)이 함께 생성된다. 또한 Main Application을 실행하는 jar런처(JarLauncher.class)를 사용해 jar 파일을 실행한다.

spring-boot-maven-plugin이 패키징을 위와같이 해준다.


스프링 부트 원리 정리

spring-boot-starter

의존성 관리

  • 의존성 관리를 받는 원리
    • Maven의 spring-boot-starter-parent, spring-boot-dependencies이다.
      • spring-boot-dependencies : Spring Boot 주요 라이브러리들의 버전 관리

자동설정

  • @SpringBootApplication안에는 다음이 들어있다.
    • @EnableAutoConfiguration
    • @ComponentScan

Spring Boot의 Bean 등록 단계

  1. ComponentScan에서 Bean 스캔해 등록
  2. 등록된 정보를 바탕으로 jar 파일 내의 META-INF 중 spring.factories 안의 auto-configuration 클래스 목록들을 참조해서 자동 설정을 시작한다.
    • 이 때 원래 있던 Bean에 기반한다.
      • @ConditionalOnMissingBean : 기존에 그런 Bean이 없으면 자동설정으로 등록한다.

내장 Tomcat

Spring Boot의 주요 특징 중 하나는 Standalone Application(독립적으로 실행 가능한 애플리케이션)을 만들어 준다는 것이다.

그렇기 때문에 내장 웹서버에 대한 기능이 잔뜩 들어가있는 것이다.

profile
https://dsunni.tistory.com/ 이사갑니답

0개의 댓글