달력

11

« 2024/11 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

'WEB'에 해당되는 글 3

  1. 2018.07.30 스프링부트 Mybatis+H2 연동하기 (JPA 미사용)
  2. 2018.07.13 WebSocket 기초
  3. 2018.07.04 SSL 작동 원리
2018. 7. 30. 20:13

스프링부트 Mybatis+H2 연동하기 (JPA 미사용) WEB2018. 7. 30. 20:13

1. 개요

    스프링부트를 사용하여 Mybatis 기본 설정(JPA 사용 X) 
    (h2의 경우 내장 DB로 pom.xml 추가 외 별도 설정 불필요)


2. 프로젝트 구조(이클립스 JAVA EE perspective의 Project Explorer 기준)
    /MyProject
        /src/main/java
            /com.example.demo
                MyProjectApplication.java
            /com.example.demo.controller
                TestController.java
            /com.example.demo.mapper
                TestMapper.java
        /src/main/resource
            /mapper
                TestMapper.xml
            /static
            /templates
            application.properties
            mybatis-config.xml
            data.sql
            schema.sql        
        pom.xml


3. pom.xml 설정
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <groupId>com.example</groupId>
        <artifactId>MyProject</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>

        <name>MyProject</name>
        <description>Demo project for Spring Boot</description>

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.3.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>

        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>

        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>     

 

4. application.properties 설정
    spring.h2.console.enabled=true
    mybatis.config-location=classpath:mybatis-config.xml
    mybatis.mapper-locations=classpath:mappers/*.xml


5. DB 스키마 / 데이터 작성
    <schema.sql>
        create table student(
           id integer not null,
           name varchar(255) not null,
           passport_number varchar(255) not null,
           primary key(id)
        );
    <data.sql>
        insert into student values(10001,'Ranga', 'E1234567');
        insert into student values(10002,'Ravi', 'A1234568');


6. mybatis-config.xml 설정
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <mappers>
            <mapper resource="mapper/TestMapper.xml"/>
        </mappers>      
    </configuration>


7. TestController.java 작성
    @RestController
    @RequestMapping("/test/*")
    public class Test {

        @Autowired
        TestMapper testMapper;        
       
        @GetMapping("/info")
        public List<Map<String,Object>> test() {            
            return testMapper.test();
        }
    }
    
8. TestMapper.java 작성
    @Mapper
    public interface TestMapper {        
        List<Map<String,Object>> test();
    }    
    
9. TestMapper.xml 작성
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.demo.mapper.TestMapper">
        <select id="test" resultType="java.util.Map">
            select * from student
        </select>
    </mapper>


10. 테스트 
    가. 스프링부트 프로젝트 기동    
    나. 브라우저 실행
    다. h2 콘솔 접속(http://localhost:8080/h2-console > JDBC URL 칸에 jdbc:h2:mem:testdb 입력 > Connect 클릭) 후 Student 테이블 유무 확인       
    라. 주소창에 요청 입력 및 리턴 값 확인
        요청 - http://localhost:8080/test/info
        응답 - [{"PASSPORT_NUMBER":"E1234567","ID":10001,"NAME":"Ranga"},{"PASSPORT_NUMBER":"A1234568","ID":10002,"NAME":"Ravi"}]
   

'WEB' 카테고리의 다른 글

WebSocket 기초  (0) 2018.07.13
SSL 작동 원리  (0) 2018.07.04
:
Posted by SK
2018. 7. 13. 20:24

WebSocket 기초 WEB2018. 7. 13. 20:24

(레퍼런스: http://www.oracle.com/technetwork/articles/Java/jsr356-1937161.html)


Java WebSocket(웹소켓) API


1.  웹소켓 정의: 생략


2.  웹소켓 등장배경(소켓, HTTP, Polling, 웹소켓의 차이): 생략


3.  웹소켓 개발 환경(Java EE 7 등): 생략


4.  웹소켓 라이프사이클 이벤트(Java 매서드와 매핑)
    가. 클라이언트가 HTTP 핸드쉐이크 요청을 보내 연결을 시작한다
    나. 서버는 핸드쉐이크 응답을 보낸다
    다. 연결이 구성되고, 이제는 HTTP가 아닌 웹소켓으로 통신한다(서버-클라이언트가 대칭상태)
    라. 두 피어 모두 메시지를 보내고 받는다
    마. 두 피어 중 하나가 연결을 닫는다  


5.  웹소켓 프로그래밍
    가. 어노테이션 방식
        POJO에 @ServerEndpoint 어노테이션을 설정하여 웹소켓 요청을 받는 endpoint로 만든다.
        @ServerEndpoint에는 웹소켓 endpoint의 경로를 넣는다.
        ex) @ServerEndpoint("/test")
            public class TestEndpoint{...}

        위 예제 코드를 보면, "test"라는 상대경로로 endpoint가 지정되는데, 

         애플리케이션이 배포되면 ws://localhost:8080/root/test와 같은 주소로 접근가능하다.
        경로에는 내부 메서드에서 사용할 수 있는 파라미터를 포함할 수 있다. ex) "/test/{userid}"
        
        웹소켓을 시작하는 POJO(클라이언트)는 @ClientEndpoint 어노테이션을 지정해야한다. 

         클라이언트 측에서는 요청을 받지 않기 때문에 @ClientEndpoint에 경로를 넣지 않는다.        
        ex) @ClientEndpoint
            public class TestClientEndpoint{...}

            
        웹소켓 연결은 다음과 같은 코드로 수행되며, 이후 @ServerEndpoint나 @ClientEndpoint가 endpoint로 호출된다.
        ex) javax.websocket.WebSocketContainer container = javax.websocket.ContainerProvider.getWebSocketContainer();
            container.connectToServer(TestClientEndpoint.class, new URI("ws://localhost:8080/mytestserver/endpoint"));

            
        웹소켓 연결이 구성되면, Session(Session 인스턴스는 웹소켓이 닫히기 전까지 유효)이 생성되고 

         @OnOpen 어노테이션이 붙은 endpoint가 호출된다. 
        이 매서드는 다음과 같은 파라미터를 포함할 수 있다.         
        - javax.websocket.Session 파라미터 (생성된 Session)
        - EndpointConfig 인스턴스 (endpoint configuration에 대한 정보를 포함)
        - @PathParam 어노테이션이 붙은 String 파라미터 (0개 이상, endpoint 경로의 파라미터를 참조)
        ex) @OnOpen
            public void testOnOpen (Session session) {
                System.out.println (session.getId());
            }

        
        웹소켓 endpoint가 메시지를 수신하면 @OnMessage 어노테이션이 붙은 매서드가 호출 된다. 

         해당 매서드는 다음과 같은 파라미터를 포함할 수 있다.
        - javax.websocket.Session 파라미터
        - @PathParam 어노테이션이 붙은 String 파라미터 (0개 이상, endpoint 경로의 파라미터를 참조)
        - 메시지 그 자체
        ex) 송신자에게 메시지를 수신만 하는 경우
            @OnMessage
            public void testOnMessage (String txt){
                System.out.println (txt);
            }

        ex) 송신자에게 리턴 값을 주는 경우
            @OnMessage
            public String testOnMessage (String txt){
                return "I got a msg: "+txt;
            }        

        
        웹소켓을 통해 메시지를 보내는 두번째 방법은, 라이프사이클의 callback 매서드(ex @OnOpen 등의)에서 얻을 수 있는 

         Session 오브젝트를 활용하는 방법이다.
        Session 인스턴스의 getBasicRemote() 매서드는 WebSocket의 상대 쪽인 RemoteEndpoint를 리턴한다. 

         RemoteEndpoint 인스턴스는 아래와 같이 메시지를 보내는데 사용할 수 있다.
        ex) RemoteEndpoint.Basic remote = session.getBasicRemote();
            remote.sendText("hi there");

        
        웹소켓 연결이 닫힐 때, @OnClose 어노테이션이 붙은 매서드가 호출된다. 

         해당 매서드는 다음과 같은 파라미터를 포함할 수 있다.
        - javax.websocket.Session 파라미터 (WebSocket이 닫히면 사용 불가. 즉, @OnClose 매서드 리턴 후에는 사용 불가)
        - javax.websocket.CloseReason 파리미터 (웹소켓 종료의 원인이 정상종료인지 프로토콜에러인지 등)
        - @PathParam 어노테이션이 붙은 String 파라미터 (0개 이상, endpoint 경로의 파라미터를 참조)
        ex) @OnClose
            public void testOnClose (CloseReason reason) {
                System.out.println(reason.getReasonPhrase());
            }

        
        만일 에러가 수신되면 @OnError가 붙은 매서드가 호출된다.
        
    나. 인터페이스 방식
        인터페이스 방식은 어노테이션 방식과 다르게 javax.websocket.EndPoint를 상속하고 

         onOpen, onClose, onError를 오버라이드하여 구현한다.
        ex) public class testEndPoint extends javax.websocket.Endpoint{
                public void opOpen(Session session, EndpointConfig config){...}
                public void opClose(Session session, CloseReason reason){...}
                public void opError(Session session, Throwable throw){...}
            }

        
        메시지를 다루기 위해서는 다음과 같이 javax.websocket.MessageHandler를 onOpen 매서드에 등록해야한다.
        ex) public void onOpen (Session session, EndpointConfig config){
                session.addMessageHandler (new MessageHandler(){...});
            }

        
        MessageHandler는 두 개의 하위 인터페이스를 가진 인터페이스다. 

         하나는 MessageHandler.Partial 인터페이스로 메시지의 부분 전송을 알아차리고 싶을때 사용하고
        또 다른 인터페이스인 MessageHandler.Whole은 완전한 메시지의 수신을 알아차리고 싶을 때 사용한다.
        ex) public void onOpen (Session session, EndpointConfig config){
                final RemoteEndpoint.Basic remote = session.getBasicRemote();
                session.addMessageHandler (new MessageHandler.Whole<String>(){
                    public void onMessage (String txt){
                        try{
                            remote.sendString ("this is test msg: "+txt);
                        }catch (IOException e){
                            ...
                        }                        
                    }
                });                
            }


6.  메시지 유형 / 인코더 및 디코더
    가. 메시지 타입
        - 텍스트 기반 메시지
        - 바이너리 메시지
        - 퐁 메시지 (웹소켓 연결 자체에 대한 메시지)
        
    나. 메지시 유형 사용
        1) 어노테이션 방식
            각 메시지 유형마다 하나의 @OnMessage 매서드가 허용된다. 메시지 유형에 따라 허용되는 파라미터가 다르다.
            가) 매서드가 텍스트 메시지를 다루는 경우
                - 전체 메시지를 수신하는 String 
                - 전체 메시지를 수신하는 Java primitive, class
                - 부분 메시지를 수신하는 String, boolean 쌍
                - blocking 시스템에서 전체 메시지 수신하는 Reader
                - 텍스트 디코더(Decoder.Text 및 Decoder.TextStream)를 가지고 있는 endpoint를 위한 모든 object 파라미터
            나) 매서드가 바이너리 메시지를 다루는 경우
                - 전체 메시지를 수신하는 byte[] 또는 ByteBuffer
                - 부분 메시지를 수신하는 byte[], boolean 쌍 또는 ByteBuffer, boolean 쌍
                - blocking 시스템에서 전체 메시지를 수진하는 InputStream
                - 바이너리 디코더(Decoder.Binary 및 Decoder.BinaryStream)를 가지고 있는 endpoint를 위한 모든 object 파라미터
            다) 매서드가 pong 메시지를 다루는 경우
                - pong 메시지 핸들링을 위한 PongMessage
        2) 인터페이스 방식과
            각 세션은 메시지 유형마다 하나의 MessageHandler를 등록할 수 있다.
    
    다. 인코더 및 디코더
        모든 Java 오브젝트는 텍스트 기반 또는 바이너리 메시지로 인코딩될 수 있다. 
        메시지는 다른 피어로 전송되며, Java 오브젝트도 다시 디코딩되거나 웹소켓 라이브러리로 인터프리트될 수 있다.
        XML이나 JSON이 웹소켓 메시지로 사용되기도 하는데 인코딩 및 디코딩을 통해 

         Java 오브젝트를 JSON, XML로 바꾸거나 그 반대를 수행할 수 있다.
        
        인코더는 javax.websocket.Encoder 인터페이스를 구현하여 정의하고, 

         디코더는 javax.websocket.Decoder 인터페스를 구현하여 정의한다.
        endpoint 인스턴스는 가능한 인코더 및 디코더가 무엇인지 알아야한다. 
        어노테이션 방식을 사용하면, @ClientEndpoint와 @ServerEndpoint에 있는 인코더 및 디코더 엘리먼트를 통해 

         인코더 및 디코더 목록이 전달된다.
        아래 코드는 TestJavaObject 인스턴스를 텍스트 메시지로 전환하는 MessageEncoder 클래스를 어떻게 등록하는지 보여준다.
        ex) @ServerEndpoint(value = "/endpoint", encoders = MessageEncoder.class, decoders = Messagedecoder.class)
            public class TestEndpoint {
                ...
            }
            
            class MessageEncoder implements Encoder.Text<TestJavaObject>{
                @Override
                public String encode (TestJavaObject obj) throws EncodingException {
                    ...
                }
            }
          
            class MessageDecoder implements Decoder.Text<TestJavaObject>{
                @Override
                public TestJavaObject decode (String src) throws DecodeException {
                    ...
                }
                
                @Override 
                public boolean willDecode (String src){
                    // 전달 받은 String이 TestJavaObject 인스턴스로 디코딩 되어야 한다면 true 리턴
                }
            }

            
        Encoder 인터페이스는 다음과 같은 하위 인터페이스를 가지고 있다.
        - Encoder.Text (Java 오브젝트를 텍스트 메시지로 변환)
        - Encoder.TextStream (Java 오브젝트를 캐릭터 스트림에 add 함)
        - Encoder.Binary (Java 오브젝트를 바이너리 메시지로 변환)
        - Encoder.BinaryStream (Java 오브젝트를 바이너리 스트림에 add 함)

        Decoder 인터페이스는 다음과 같은 하위 인터페이스를 가지고 있다.
        - Decoder.Text (텍스트 메시지를 Java 오브젝트로 변환)
        - Decoder.TextStream (캐릭터 스트림으로부터 Java 오브젝트를 read 함)
        - Decoder.Binary (바이너리 메시지를 Java 오브젝트로 변환)
        - Decoder.BinaryStream (바이너리 스트림으로부터 Java 오브젝트를 read 함)       

'WEB' 카테고리의 다른 글

스프링부트 Mybatis+H2 연동하기 (JPA 미사용)  (0) 2018.07.30
SSL 작동 원리  (0) 2018.07.04
:
Posted by SK
2018. 7. 4. 21:34

SSL 작동 원리 WEB2018. 7. 4. 21:34

○ SSL 매커니즘

보안과 성능상 이유로 아래 두 가지 기법을 혼용하여 사용

- 대칭키

· 동일한 키로 암호화와 복호화를 같이 하는 방식

· 대칭키 유출 시 암호의 내용을 복호화할 수 있기 때문에 암호를 주고받는 사람들 사이에서 대칭키 전달이 어려움 -> 공개키로 해결

- 공개키

· 두 개의 키로 암호화, 복호화를 하는 방식(A키로 암호화 시 B키로 복호화, 그 역도 성립)

-> 두 개의 키를 각각 비공개키, 공개키로 설정하여 비공개키는 자신만 가지고 있고 타인이 공개키로 암호화한 내용을 비공개키로 복호화

-> 비공개키로 암호화 후 공개키와 함께 암호화된 정보 전송하여 데이터가 공개키와 쌍을 이루는 비공개키로 암호화 된 것을 증명(전자서명)

○ SSL 인증서

- SSL 인증서 기능

· 통신 내용이 공격자에게 노출되는 것을 방지

· 클라이언트가 접속한 서버가 신뢰 할 수 있는 서버임을 보장

  (CA(Certificate Authority 또는 Root Certificate)라는 기업들에 의해 수행

  ex) Symantec, Comodo 등)

· SSL 통신에 사용할 공개키를 클라이언트에게 제공

- SSL 인증서 내용

· 서비스의 정보(인증서를 발급한 CA, 서비스의 도메인 등)

· 서버 측 공개키(공개키의 내용, 공개키의 암호화 방법)

 -> CA는 자신의 비공개키를 이용하여 서버가 제출한 인증서를 암호화

○ SSL의 동작

- 신뢰할 수 있는 서비스 증명: 웹브라우저가 서버에 접속 > 서버가 인증서 제공 > 제공된 인증서의 CA가 브라우저에 내장된 CA리스트내에 있는지 확인 > CA의 공개키를 이용해 인증서 복호화 > 복호화가 되면 인증서가 해당 CA의 비공개키에 의해 암호화된 것이므로 신뢰할 수 있는 서비스인 것이 증명

- 데이터 암호화: 네트워크 통신(악수 → 전송 → 세션종료)시 SSL이 데이터를 암호화함(실제 데이터는 대칭키로, 대칭키의 키는 공개키로 암호화)

· 악수(handshake):

1) 클라이언트가 서버에 접속(Client Hello) 및 주고받는 데이터:

 ☞ 클라이언트 측에서 생성한 랜덤 데이터

 ☞ 클라이언트가 지원하는 암호화 방식(클라이언트와 서버가 지원하는 암호화 방식이 달라, 어떤 암호화 방식을 사용할 것인지 협상 필요)

 ☞ 세션 아이디: 추후 악수 과정을 생략하기 위해 사용자 세션을 서버로 전송

2) 서버 측 응답(Server Hello) 및 주고받는 데이터

 ☞ 서버 측에서 생성한 랜덤 데이터

 ☞ 서버가 선택한 클라이언트 암호화 방식

 ☞ 인증서

3) 클라이언트가 내장된 CA리스트 확인 및 해당 CA의 공개키를 통한 복호화 과정을 거쳐 신뢰할 수 있는 서버인지 확인 > 클라이언트가 클라이언트 랜덤 데이터와 서버 랜덤 데이터를 조합하여 대칭키(pre master secret)를 생성 > 서버로부터 받은 인증서에 들어있는 공개키를 이용해서 pre master secret값을 암호화 후 서버로 전송

4) 서버가 전송받은 pre master secret값을 자신의 비공개키로 복호화(서버와 클라이언트 모두 pre master secret을 공유) > 서버가 pre master secret값을 일련의 과정을 거쳐 master secret값으로 생성 > master secret이 session key를 생성 > session key값을 이용하여 클라이언트와 서버간 데이터를 대칭키 방식으로 암호화하여 전송(서버와 클라이언트 모두 session key를 공유)

5) 클라이언트와 서버가 악수단계 종료를 서로에게 알림

· 세션(정보를 주고 받는 단계): 정보를 상대방에게 전송시 session key값을 이용해 대칭키 방식으로 암호화, 상대방은 해당 대칭키를 통해 복호화

* 공개키 방식이 많은 컴퓨터 파워를 사용하기 때문에 많은 접속이 물리는 서버에 큰 부하를 가져오며, 대칭키 전송시 암호화 되지 않는 인터넷을 통해서 전송하는 것은 위험

-> 속도는 느리지만 데이터를 안전하게 주고받을 수 있는 공개키로 대칭키를 암호화하여 실제 데이터 전송시에는 대칭키를 사용

· 세션종료: 데이터 전송이 끝나면 SSL통신이 끝났음을 서로에게 알리고 session key 폐기



□ HTTP vs HTTPS(Hypertext Transfer Protocol Over Secure Socket Layer)

○ 차이점

HTTP의 보안을 강화한 것이 HTTPS로 SSL프로토콜 위에서 돌아가는 프로토콜임. HTTP는 암호화되지 않은 방법으로 데이터를 전송하기 때문에 서버와 클라이언트 간의 메시지를 감청당할 위험이 있음.

○ 모든 웹사이트가 HTTPS를 쓰지 않는 이유

- 보안인증 비용, SSL(or TLS) 키 교환 시 호출시간 소요(웹 서버 부하),

- 불특정 다수에게 공개해도 상관없는 페이지는 http로, 메일이나 로그인 등의 페이지는 https로 하는 것이 효율적

'WEB' 카테고리의 다른 글

스프링부트 Mybatis+H2 연동하기 (JPA 미사용)  (0) 2018.07.30
WebSocket 기초  (0) 2018.07.13
:
Posted by SK