패키지 설치

npm install --save mysql2
npm install --save-dev @types/node

 

모듈화

import mysql, {ConnectionOptions, ResultSetHeader, RowDataPacket} from "mysql2/promise";
import "../config/env";
import {DatabaseError} from "../middleware/errors/DatabaseError";

const access: ConnectionOptions = {
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
    port: Number(process.env.DB_PORT || "3306"),
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0,
    connectTimeout: 10000, // MySQL 서버에 연결할 때의 타임아웃(ms 단위)
    enableKeepAlive: true // 연결이 일정 시간 동안 비활성 상태일 때에도 끊어지지 않도록
};

export const database = mysql.createPool(access);

export const selectList = async <T extends RowDataPacket>(statement: string): Promise<T[]> => {
    let connection;

    try {
        connection = await database.pool.promise().getConnection();
        const result = await connection.query<T[]>(statement);
        return result[0];
    } catch (e: unknown) {
        if (e instanceof Error) {
            throw new DatabaseError(e.message);
        }
        throw new Error("DB Unexpected Error");
    } finally {
        if (connection) {
            connection.release();
        }
    }
};

export const selectOne = async <T extends RowDataPacket>(statement: string): Promise<T> => {
    let connection;

    try {
        connection = await database.pool.promise().getConnection();
        const result = await connection.query<T[]>(statement)

        return result[0][0];
    } catch (e: unknown) {
        if (e instanceof Error) {
            throw new DatabaseError(e.message);
        }
        throw new Error("DB Unexpected Error");
    } finally {
        if (connection) {
            connection.release();
        }
    }
};

export const mutation = async (statement: string): Promise<ResultSetHeader> => {
    let connection;

    try {
        connection = await database.pool.promise().getConnection();
        const result = await connection.query<ResultSetHeader>(statement);
        return result[0];
    } catch (e: unknown) {
        if (e instanceof Error) {
            throw new DatabaseError(e.message);
        }
        throw new Error("DB Unexpected Error");
    } finally {
        if (connection) {
            connection.release();
        }
    }
}

 

사용 방법

import {mutation, selectList, selectOne} from "../../config/db";
import {ResultSetHeader} from "mysql2/promise";
import UserType from "../../types/UserType";

class UserModel {
	static async getAllUsers(): Promise<UserType[]> {
        const statement = `
          SELECT USER_ID
          FROM USER_TABLE
        `;

        return await selectList<UserType>(statement);
      }

      static async getUserById(USER_ID: string): Promise<UserType> {
        const statement = `
          SELECT USER_ID
          FROM USER_TABLE
          WHERE USER_ID = '${USER_ID}'
        `;

        return await selectOne<UserType>(statement);
      }

      static async createUser(user: UserType): Promise<ResultSetHeader> {
        const statement = `INSERT INTO ...`
        return await mutation(statement);
      }
  
      tatic async updateUser(user: UserType): Promise<ResultSetHeader> {
        const statement = `UPDATE ...`
        return await mutation(statement);
      }
      
      static async deleteUser(user: UserType): Promise<ResultSetHeader> {
        const statement = `DELETE ...`
        return await mutation(statement);
      }
  }

export default UserModel;

 

 


 

 

Using MySQL2 with TypeScript | Quickstart

Installation

sidorares.github.io

 

'JavaScript > TypeScript' 카테고리의 다른 글

[TS] Express 속성 타입 추가하기  (0) 2024.06.17

 

모듈 설치

npm i express
npm i @types/express

 

# src/middleware/guard.ts
import {NextFunction, Request, Response} from "express";

export default (req: Request, res: Response, next: NextFunction) => {
    try {
        ...
        
        req.session = {
            LOGIN_ID: decodeTokenJson.LOGIN_ID
        }
        next();
    } catch (e: unknown) {
        next(e);
    }
}

JWT 검증에 성공한다면,  Request 정보에 LOGIN_IN 속성을 추가하여 뒷 단에서 decode한 값들은 사용하려 한다

 

# src/types/express/index.d.ts
import * as express from "express"

declare global {
  namespace Express {
    interface Request {
      session: {
        LOGIN_ID: string;
      }
    }
  }
}

types/express/index.d.ts 파일을 생성하여, 원하는 속성 타입을 추가한다

 

# tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",          /* JavaScript 버전 */
    "module": "commonjs",        /* 모듈 시스템 */
    "outDir": "./dist",          /* 컴파일된 파일 출력 디렉토리 */
    "rootDir": "./src",          /* 소스 파일 디렉토리 */
    "strict": true,              /* 엄격한 타입 검사 */
    "esModuleInterop": true,     /* ES 모듈과의 상호 운용성 */
    "skipLibCheck": true,         /* 라이브러리 체크 건너뛰기 */
    "typeRoots": ["./src/types", "./node_modules/@types"]
  }
}

typeRoots 속성을 추가한다. 중요한 것은  node_modules/@types 의 값이 나중에 선언되어야 적용된다

'JavaScript > TypeScript' 카테고리의 다른 글

[TS] mysql2 패키지 모듈화  (0) 2024.06.17

MongoDB 설치

# 파일 생성
vi /etc/yum.repos.d/mongodb-org-5.0.repo

# 파일 작성
[mongodb-org-5.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/5.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-5.0.asc

# 파일 생성 완료 후, 설치
yum repolist
yum install -y mongodb-org

# 서비스 시작, 상태 확인
systemctl start mongod
systemctl status mongod

 

포트 변경, 접속 허용 IP 설정

# 파일 수정
vi /etc/mongod.conf

# network interfaces
net:
   port: 27017
   bindIp: 127.0.0.1

 

# network interfaces
net:
   port: 22222
   bindIp: 127.0.0.1,123.123.123.123
   bindIpAll: true
   
security:
   authorization: enabled

MongoDB의 기본 포트는 27017이지만 특정 포트(ex. 22222)로 변경이 가능하다

기본적으로 설치 PC에서만 접속 가능하도록 설정이 되어있어서,  다른 IP (ex. 123.123.123.123)에서도 접속 가능하도록 설정했다

각 IP들은 쉼표(,)로 구분해주어야 하고, bindIpAll 옵션을 추가해야 한다

 

security 옵션은 클라이언트에서 연결 시, 계정을 요구하도록 설정할 수 있다

 

 

 

방화벽 설정

# 방화벽 목록 확인
firewall-cmd --permanent --list-all

# 방화벽 추가
firewall-cmd --permanent --zone=public --add-port=22222/tcp

# 재시작 (적용)
firewall-cmd --reload

# 방화벽 설정 제거
firewall-cmd --permanent --zone=public --remove-port=22222/tcp

 

'데이터베이스 > MongoDB' 카테고리의 다른 글

[NoSQL] NodeJS + MongoDB(mongoose)  (0) 2022.09.12
[NoSQL] MongoDB 설치 - Mac  (0) 2022.09.10

brew 설치

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Homebrew Site


 

MySQL 설치,  설정

# Installation
$ brew install mysql

# version
$ mysql -V

# server start
$ mysql.server start

# server stop
$ mysql.server stop
$ mysql_secure_installation

 

 

root password를 설정하지 않았는데 입력하라고 나오고, 진행이 불가능
brew services list 확인 시, mysql none 확인. brew serviecs start mysql 입력을 통해 started 상태로 변경

# brew command
# list
$ brew services list

# mysql start
$ brew services start mysql

# mysql stop
$ brew services stop mysql

# mysql restart
$ brew services restart mysql

mysql_secure_installation 명령어를 입력해 루트 비밀번호를 설정해 준다

$ mysql -u root -p

루트 비밀번호가 설정되었는지 root 사용자 로그인을 해본다

루트 계정 비밀번호 변경

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '변경할-비밀번호';
mysql> FLUSTH PRIVILEGES;

 

데이터베이스 생성, 사용자 생성

# mysql 쉘 접속
> mysql -u root -p

# database 확인
mysql> show databases;

# database 생성
mysql> create database [database name];

# user 생성
# %는 모든 IP 대해서 해당 계정으로 접속 가능하다는 뜻. 본인 컴퓨터에서 접속하려면 127.0.0.1 또는 localhost 로 설정
mysql> create user 'sejin'@'%' identified by 'userPw';

# user 권한 부여
mysql> grant all privileges on [database name].* to 'sejin'@'%';

# 권한 적용 (변경된 내용을 메모리에 반영)
mysql> flush privileges;

# database 접속
mysql> use [database name];

# shell 환경으로 나와서 생성된 계정으로 접속
mysql> exit
> mysql -u userId -p

 

user 생성 확인 완료

 

계정 접속 IP 제한

mysql> use mysql
mysql> select host,user from user;
mysql> update user set host = 'IP 입력(xxx.xxx.xxx.xxx)' where user = 'userId';
mysql> flush privileges;

 

 

외부 접속 설정

맥북에서 homebrew를 통해 mysql을 설치했고 my.cnf를 통해 포트를 열어줄 수 있다

파일 위치는 /usr/local/etc/my.cnf 에 있었음 (경로는 다를 수 있음)

# vi /usr/local/etc/my.cnf

# 파일 내용
[mysqld]
bind-address = 127.0.0.1
mysqlx-bind-address = 127.0.0.1

bind-address 값을 0.0.0.0 (모든 IP 요청 허용) 으로 변경한다  → 이제부터 포트 요청이 가능함 (telnet으로 접속 가능)

내부 IP에서의 접속이 아닌 외부망을 통해 접속하려면 포트포워딩 설정을 해주어야함

 

 


MySQL DB Tools

1. VSCode Extensions (MySQL)

2. HeidiSQL (윈도우 전용)

3. DBeaver

4. MySQL Workbench

 


참고 링크

Github losskatsu
Tistory jaynamm

https://nickjoit.tistory.com/144

 

Redux 상태 관리 라이브러리

 

저장된 데이터를 전역에서 관리

 


NPM 설치

npm i redux
npm i react-redux
npm i @reduxjs/toolkit

 

폴더 구조 (expo)

 

App.tsx

import { Provider } from "react-redux";
import Main from "./src/screens/Main";
import store from "./src/store";

export default function App() {
  return (
    <Provider store={store}>
      <Main />
    </Provider>
  );
}

 

src/slices/counter.ts

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  count: 0,
};

const countSlice = createSlice({
  name: "count",
  initialState,
  reducers: {
    plusCount(state) {
      state.count += 1
    },
    minusCount(state) {
      state.count = state.count - 1;
    },
    setCount(state, action) {
      state.count = action.payload.count;
    },
  },
});

export default countSlice;

 

src/store/reducer.ts

import { combineReducers } from "redux";
import countSlice from "../slices/counter";

const rootReducer = combineReducers({
    countReducer: countSlice.reducer
});

export type RootState = ReturnType<typeof rootReducer>;
export default rootReducer;

 

src/store/index.ts

import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "./reducer";
import { useDispatch } from "react-redux";

const store = configureStore({
    reducer: rootReducer,
    middleware: getDefaultMiddleware => {
        return getDefaultMiddleware();
    }
});

export default store;
export type AppDispatch = typeof store.dispatch;
export const useAppDispatch = () => useDispatch<AppDispatch>();

 

src/screens/Main.tsx

import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
import { useSelector } from "react-redux";
import countSlice from "../slices/counter";
import { useAppDispatch } from "../store";
import { RootState } from "../store/reducer";

const Main = () => {
  const dispatch = useAppDispatch();
  const count = useSelector((state: RootState) => state.countReducer.count);

  const setCounter = (value: number) => {
    dispatch(
      countSlice.actions.setCount({
        count: value,
      })
    );
  };

  return (
    <View style={styles.container}>
      <View style={styles.view_container}>
        <Text>{count}</Text>
      </View>
      <View style={styles.button_container}>
        <TouchableOpacity
          style={StyleSheet.compose(styles.button, { backgroundColor: "blue" })}
          onPress={() => dispatch(countSlice.actions.plusCount())}
        >
          <Text style={styles.button_text}>+</Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={StyleSheet.compose(styles.button, { backgroundColor: "red" })}
          onPress={() => {
            if (count > 0) {
              dispatch(countSlice.actions.minusCount());
            }
          }}
        >
          <Text style={styles.button_text}>-</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  view_container: {
    flex: 1,
    justifyContent: "center",
  },
  button_container: {
    flex: 1,
    flexDirection: "row",
  },
  button: {
    width: 100,
    height: 100,
    alignItems: "center",
    justifyContent: "center",
    borderRadius: 20,
    margin: 20,
  },
  button_text: {
    fontWeight: "bold",
    color: "#ffffff",
    fontSize: 30,
  },
});

export default Main;

 

 


 

 

Installation | Redux

Introduction > Installation: Installation instructions for Redux and related packages

redux.js.org

 

'JavaScript > React Native' 카테고리의 다른 글

[React Native] 프로젝트 생성  (0) 2024.01.14

리액트 네이티브 (React Native)는 페이스북에서 개발한 오픈 소스 프레임워크

JavaScript (+ TypeScript), React를 사용하여 안드로이드, iOS 앱을 개발할 수 있다

 

일반적으로 하나의 코드 작성을 통해 안드로이드, iOS 앱을 개발할 수 있지만, 각 플랫폼마다 지원하는 함수가 다른 경우가 있다

 

프로젝트 방식에는 React Native CLIExpo 방식이 있다

 

Expo 방식은  안드로이드, IOS 에서 Expo Go 어플을 통해서 같이 네트워크 안에 있다면 QR 코드로 쉽게 스마트폰에서 실시간으로 확인하면서 쉽게 개발할 수 있고, Expo에서 제공하는 모듈들이 많기 때문에 편했다

그리고 확실히 개발 속도가 빠르다는 것을 느꼈다

 

React Native CLI 방식을 이용하면 안드로이드 스튜디오에서 제공하는 에뮬레이터와 XCode의 시뮬레이터를 통해 실시간으로 확인하면서 개발이 가능하고, 그렇지 않다면 스마트폰에 USB를 연결해서 확인도 가능하다. (Expo도 에뮬레이터, 시뮬레이터로 확인 가능)

처음 시작했을때 환경 설정하는 것도 어렵고, android, ios 폴더를 별도로 있어 파일의 양이 많다. 환경 구축이 되어 있지 않다면 초기에 어려운 과정으로 인해 개발 속도가 매우 느릴 수 있음

하지만 안드로이드, IOS의 네이티브 모듈을 건들기 위해서는 CLI 방식을 택해야 한다

 

외주 프로젝트를 시작할 때,  개발 속도가 빠르고 편한 Expo 방식을 사용했다

문제는 Expo에서 제공하는 무료 배포 방식을 사용했었는데, 저녁 시간 대 사용하면 1시간 넘게 기다리기도 했다

마냥 대기 시간을 기다려야 했기 때문에 빠르게 포기하고,  React Native CLI로 변경해서 개발했다

 

Expo에서 유료 플랜을 사용하면, 배포 속도가 빠르다고 하는데 가격이 비싼 것 같다

실제 서비스라면 React Native CLI로 개발하는 것이 좋을 것 같다

 

프로젝트 생성

# React Native CLI  *
npx react-native init [project name]
npx react-native init specificVerProject --version=0.69 # 특정 버전 설치

# expo 설치
npm install --global expo-cli

# expo project 생성
npx create-expo-app # javascript
npx create-expo-app --template # typescript

# bun
bunx create-expo-app # javascript

 

 

프로젝트 실행

npm run start
npm run android
npm run ios

 

  • 안드로이드인 경우, 안드로이드 스튜디오와 에뮬레이터 (Emulator)를 설치
  • iOS인 경우, Xcode와 시뮬레이터 (Simulator)를 설치

 

'JavaScript > React Native' 카테고리의 다른 글

[React Native] Redux 상태 관리  (0) 2024.01.21

vi ~/.bashrc
source ~/.bashrc

bashrc 파일에 export LD_LIBRARY_PATH 추가 적용하고,  일반적인 명령어조차 실행할 수 없다

cd 명령어는 실행 가능

 

echo $LD_LIBRARY_PATH
unset LD_LIBRARY_PATH

 

추가한 환경변수를 확인해보고,  환경변수를 제거시켜 준다

바로 정상적으로 리눅스를 쓸 수 있다

'Linux' 카테고리의 다른 글

맥북 VirtualBox Ubuntu 설치  (0) 2023.09.02

 

 

폴더/계층 구조는 이렇다

많은 블로그, 정보들을 확인 봤지만 쉽지 않다. MyBatis 설정을 간단하게 해 보자

 


 

https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure

  • build.gradle
    1. org.springframework.boot version 확인
    2. java - sourceCompatibility 확인
    3. dependencies [ https://mvnrepository.com ]
      1. mysql-connector-java
      2. mybatis-spring-boot-starter
plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.15'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

java {
	sourceCompatibility = '8'
}

dependencies {
	implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.28'
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.0'
}

MyBatis 설정이 쉽지 않았는데, 아마 버전 충돌을 의심해 볼 수 있었다

springboot 프로젝트 생성 시, 기본적으로 Springboot 버전은 3.1이었고, java 버전은 17로 선언되어 있었다

MyBatis 공식 사이트 Requirements 버전 호환성에 맞게 설정해 주었다

 

dependencies 수정 후, Gradle Refresh !! 부트 버전 변경 같은 경우에는 Spring 항목 이용함

  • application.yml
server:
  port: 8000
  
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=Asia/Seoul
    username: MySQLId
    password: MySQLPassword

mybatis:
  type-aliases-package: com.example.demo
  mapper-locations: mybatis/mapper/**/*.xml

type-aliases-package을 통해 별칭을 설정할 수 있다

com.example.demo 까지 선언하였지만 아래 경로까지 다 인식해 주는 걸로 확인했다

<!-- before -->
<select id="getAllUsers" resultType="com.example.demo.user.model.User">
<!-- after -->
<select id="getAllUsers" resultType="User">

중요한 것은 class 이름만 선언해야 한다 (user.model.User ❌ model.User ❌   User ⭕️ )

 

mapper-locations 설정은 mapper.xml 위치를 알려준다.

mybatis/mapper/*.xml 일 경우는 mapper 폴더 내의 xml 파일을 인식하지만

**/*.xml 로 선언할 경우, mapper/ ... folder1 / ... folder2 / *.xml  하위 경로에 있는 모든 xml 파일들을 인식한다

 

 

  • UserMapper.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.UserMapper">
    <select id="getAllUsers" resultType="User">
        SELECT * FROM User
    </select>
</mapper>
  • UserMapper.java
package com.example.demo.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import com.example.demo.user.model.User;

@Mapper
public interface UserMapper {
	
	List<User> getAllUsers() throws Exception;
	
	@Select("SELECT * FROM User")
	List<User> selectAnnotation() throws Exception;
	
}
  1. Java(Interface) , XML 파일의 이름이 동일할 필요는 없다. 하지만 XML namespace 경로를 잘 지정해주어야 한다
  2. Java(Interface)에 선언한 함수 이름과 XML에 선언한 id는 동일해야 한다
  3. XML 파일을 활용하지 않는다면, @Select, @Insert, @Update, @Delete, @Results 어노테이션을 활용할 수 있다

 

  • UserServiceImpl.java
package com.example.demo.user.service.impl;

import java.util.List;

import org.springframework.stereotype.Service;

import com.example.demo.mapper.UserMapper;
import com.example.demo.user.model.User;
import com.example.demo.user.service.UserService;

@Service
public class UserServiceImpl implements UserService {

	private UserMapper userMapper;

	public UserServiceImpl(UserMapper userMapper) {
		this.userMapper = userMapper;
	}

	@Override
	public List<User> getAllUser() throws Exception {
		List<User> list = userMapper.getAllUsers();
		return list;
	}

}

설정을 완료하였고, 이제 Mybatis를 사용할 수 있다

 

데이터베이스 연결 부분에서 문제가 생길 수도 있다. 계정과 권한을 확인해야 한다. (아래 참고링크 확인)

계정을 새로 만들었다면, 데이터베이스에 대한 권한을 부여해야 한다

 

그리고 DateTime 타입의 컬럼을 조회했을 때,  (실제 DB 값에는 T 문자가 없음에도 불구하고) "2023-09-10T 02:00:13"이라고 나올 수 있다

package com.example.demo.user.model;

import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

@Data
public class User {
	String id;
	String password;
	String name;
	int age;

	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	LocalDateTime createDt;
	
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	LocalDateTime updateDt;
	
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	LocalDateTime deleteDt;
}

@JsonFormat을 사용하면 API 결과 값에서 T가 제거된 것을 확인할 수 있다


참고 링크

 

mybatis-spring-boot-autoconfigure – Introduction

Introduction Translations Users can read about MyBatis-Spring-Boot-Starter in the following translations: What is MyBatis-Spring-Boot-Starter? The MyBatis-Spring-Boot-Starter help you build quickly MyBatis applications on top of the Spring Boot. By using t

mybatis.org

 

mysql 사용자추가/DB생성/권한부여

서버 관리를 하다보면 mysql 사용자 계정을 추가해 줄때가 있다. MySQL 접속 및 데이터 베이스 추가# mysql -u root -p 사용자 계정을 추가하기 전에 먼저 현재 생성된 사용자 계정을 확인한다. mysql > use

nickjoit.tistory.com

'JAVA > Spring' 카테고리의 다른 글

[Springboot] MVC 패턴과 폴더 구조  (0) 2023.09.04
[Springboot] Lombok  (0) 2023.09.04
[Springboot] 스프링부트 시작하기  (0) 2023.09.03

 

HTTP (Hypertext Transfer Protocol)

  • 웹 브라우징을 위한 기본 프로토콜로, 웹 브라우저와 웹 서버 간의 데이터 전송을 담당
  • 텍스트 기반의 프로토콜로, 데이터를 평문으로 전송
  • 기본 포트 번호는 80을 사용

 

HTTPS (HTTP  Secure)

  • 말 그대로 HTTP의 보안 버전으로 데이터를 암호화하여 보안을 강화
  • 데이터의 안전한 전송을 위해 SSL/TLS 프로토콜을 사용 (HTTPS = HTTP + SSL/TLS)
  • 데이터 무결성을 보장한다. 데이터가 전송 중에 변경되지 않았음을 확인한다.
  • 기본 포트는 443을 사용

 


 

HTTPS의 동작 원리

 

사전 개념

 

대칭키 암호화 방식

 

하나의 암호화 키(KEY)로 평문 암호화/복호화 모두 할 수 있는 방식이다.

집 대문의 자물쇠를 생각해보자. 열쇠를 통해 문을 잠그고 열고 모두 가능하다.

하지만 열쇠를 잃어버린다면 열쇠를 주운 사람이 우리 집을 마음대로 드나들 수 있다.

마찬가지로 대칭키 방식은 키를 분실하였을 때, 누군가가 나의 정보를 볼 가능성이 있다는 치명적인 단점이 있다

 

 

공개키 암호화 방식

 

공개키, 개인키 2개의 키를 한 쌍 (pair)로 각각 암호화/복호화에 사용한다.

일반적으로 공개키로 데이터를 암호화하고,  개인키로 암호화된 데이터를 복호화한다. 

개인키를 먼저 만들고, 여기서 공개키를 파생하여 한 쌍의 키를 만들기 때문에 키페어라고 한다

공개키 방식은 대칭키 방식에 비해 안전하지만, 계산 과정이 복잡하고 연산 도중 컴퓨터 자원을 많이 사용하기 때문에

안전하게 통신할 수 있지만 속도가 느리다는 단점이 있다. 실제 시스템에서는 공개키 방식과 대칭키 방식을 적절하게 혼합하여 사용한다

 

 

CA (Certificate Authority, 인증 기관)

 

SSL을 적용하기 위해서는 인증서가 필요한데, 인증서를 발급해주는 기업이나 단체를 CA라고 한다. 

인증서에는 서비스의 정보와 서버 측의 공개키를 포함하고 있다. 브라우저는 CA 리스트를 가지고 있다.

대표적으로 Digicert, Sectigo, GlobalSign, Let's Encrypt 등이 있습니다.


 

HTTPS 동작 원리

크게 핸드 셰이크(handshake), 세션, 세션 종료 3단계로 이루어진다

 

핸드 셰이크

1. 클라이언트는 서버에게 인사를 건넨다 (Client Hello). 랜덤한 데이터와 현재 지원할 수 있는 암호화 방식을 서버에게 전달한다. 암호화 방식을 전달하는 이유는 같은 대칭키, 공개키 기법이라도 다양한 암호화 방식이 있기 때문에 서로 어떤 암호화 방식을 사용할지 협의하는 과정이 필요하기 때문이다

 

2. 클라이언트의 인사를 받은 서버는 클라이언트에게 인사를 건넨다 (Server Hello). 서버는 3가지 내용을 전달한다 (랜덤 데이터, 지원 가능한 암호화 방식, 인증서 - CA에서 발급받은 문서로 서버가 신뢰할 수 있는지 보장하는 역할을 한다)

 

3. 인증서를 받은 클라이언트는 유효한 인증서인지 검증하기 위해, CA가 발급한 인증서 목록 중 서버가 전달한 인증서가 있는지 확인한다. 이후 CA에서 공유하는 공개키를 가지고 인증서를 복호화한다. 만약 복호화가 되었다면 인증서는 해당 CA에서 발급되었다는 것을 검증한 것이기 때문에 서버를 신뢰할 수 있다

 

4. 본격적으로 키를 주고받기 위해 클라이언트는 실제 데이터 통신에서 사용할 대칭키를 임시로 만든다. 앞서 클라이언트와 서버가 서로 주고받은 랜덤한 데이터를 조합해 임시 키를 생성하는데, 임시키는 대칭키이기 때문에 절대 제 3자에게 노출되면 안되기 때문에 앞서 갖고 있던 공개키로 암호화해 서버에게 전달한다

 

5. 키를 받은 서버는 자신이 갖고 있던 비밀키로 암호를 해독하여 임시키를 전달받게 된다. 비로소 서버/클라이언트는 같은 키를 공유한다

 

6. 클라이언트와 서버의 임시 키는 일련의 과정을 거쳐 세션키로 바뀌고, 이 세션키를 이용해 통신을 할 수 있다

 

세션과 세션 종료

그 이후 단계인 세션 단계에서는 앞서 생성한 세션키를 이용해 대칭키 기법으로 데이터를 암호화해서 통신하고, 데이터 전송이 끝나면 세션을 종료해 통신을 마친다. 이 때 통신에서 사용한 세션키도 삭제한다.


 

 

두 프로토콜의 가장 큰 차이는 보안이다. HTTP는 데이터를 암호화하지 않기 때문에 중간자 공격과 데이터 도난의 위험이 있다.

HTTPS는 데이터를 암호화하기 때문에 이러한 위험을 최소화한다. - 완벽한 보안은 없다

 

 

HTTPS와 SEO (Search Engine Optimization, 검색 엔진 최적화) 연관성

 

  • 구글과 다른 검색 엔진은 웹사이트의 보안을 고려하여 검색 순위를 조정한다. HTTPS를 사용하는 웹사이트는 일반적으로 검색엔진에서 높은 순위를 받을 가능성이 높은데, HTTPS는 사용자 데이터 보호와 웹 보안을 강화하기 때문
  • HTTPS를 사용하는 웹사이트는 보안 배지 또는 그린 로킹 표시와 같은 시각적 표시를 통해 사용자에게 웹사이트의 신뢰성을 쉽게 전달할 수 있다

HTTPS
HTTP

 


SSL (Secure Sockets Layer)

 

- 넷스케이프(Netscape)에서 개발된 보안 프로토콜로, 데이터의 기밀성과 무결성을 제공

- 데이터를 암호화하고, 클라이언트 및 서버 간의 신뢰성있는 통신을 확립하기 위해 디지털 인증서를 사용

 

TLS (Transport Layer Security)

 

- SSL 3.0 버전을 기반으로 하며, SSL의 취약점을 보완하고 보안 향상을 위해 여러 버전으로 발전

- 데이터 통신을 보호하고, 기밀성, 무결성 및 인증을 제공

 

 

TLS는 SSL의 후속 버전이며, 이제 모든 버전의 SSL은 더 이상 사용되지 않는다고 한다. (대부분 SSL 및 SSL/TLS라는 용어 모두 TLS 프로토콜과 TLS 인증서를 뜻 함, TLS 인증서가 업계 표준)

 

SSL에서 TLS로 이름이 변경된 지 오래됐지만 아직도 사람들은 TLS 대신 SSL이라는 표현을 더 많이 사용하고 있으며 실제로 SSL/TLS의 오픈소스 구현체 프로젝트 명칭은 OpenSSL이라고 한다.

 

 


참고 링크

 

 

그림으로 쉽게 보는 HTTPS, SSL, TLS

SSL과 TLS는 무슨 차이일까 | 지난 포스팅에서 웹 브라우저와 웹 서버 간에 데이터를 주고받기 위해 사용하는 인터넷 프로토콜인 HTTP에 대해 알아봤습니다. 1996년에 탄생한 이후부터 지금까지 HTTP

brunch.co.kr

 

안전한 웹을 위해 HTTPS 이해하기: ①HTTPS의 작동 원리 | 요즘IT

웹에서는 내가 원하는 정보를 열람하는 것뿐만 아니라, 내가 입력한 정보를 웹 사이트를 운영하는 회사의 시스템으로 전달하는 경우도 많습니다. 예를 들어, 포털 사이트에 내 계정 정보를 입력

yozm.wishket.com

 

[네트워크] HTTPS의 개념과 동작 원리

HTTPS는 HTTP에 보안이 강화된 프로토콜이라는 것을 알고있다. 프로젝트를 진행하면서 SSL 인증서를 발급받아 HTTPS로 요청할 수 있도록 했던 경험도 있다. 하지만 정확히 HTTPS가 어떻게 동작하는지

kimmeh1.tistory.com

 

HTTP HTTPS 차이: 당신의 웹 사이트는 안전한가요? - 어센트 코리아

HTTP와 HTTPS의 차이점과 각각의 정의 및 Google 랭킹 팩터 여부에 대한 자세한 내용을 알아보겠습니다.

www.ascentkorea.com

 

SSL/TLS 와 HTTPS

 

www.lesstif.com

 

MVC 패턴?

 

Model, View, Controller 의 앞글자를 딴 디자인 패턴이다. 

 

 

Model, 모델

  • 데이터를 처리하는 영역 (데이터와 비즈니스 로직을 관리)
  • 데이터베이스 연동을 위한 DAO (Data Access Object)와 데이터 구조를 표현하는 DO (Data Object)로 구성

 

View, 뷰

  • 사용자에게 정보를 표시하는 역할
  • 웹 사이트, 어플과 같은 사용자 인터페이스 (UI)를 의미
  • 별도의 데이터를 보관하지 않음

 

Controller, 컨트롤러

  • 모델과 뷰 사이에서 브릿지(bridge) 역할을 수행
  • 사용자의 요청은 모두 컨트롤러를 통해 진행되어야 함

특 징

  • 어플리케이션의 역할을 세 가지 주요 부분으로 나누어 설계함으로써 서로 간의 의존성이 낮아짐
  • 독립적인 각 부분은 영향을 주지 않기 때문에, 유지 보수와 테스트하기 용이하고, 개발자 간 분업 및 협업이 원활해짐

 

단 점

  • 간단한 프로젝트에 MVC 패턴을 도입하는 것은 오버헤드일 수 있다. 모델-뷰-컨트롤러로 분리하는 구조는 큰 프로젝트에 더 유용하며, 작은 프로젝트에서는 과도한 구조화일 수 있다
  • 컨트롤러의 역할이 너무 커져 복잡해질 수 있다. "Massive-View-Controller" MVC 패턴을 구현할 때 발생하는 문제 중 하나를 가리키는 용어이다. 
    1. 다수의 뷰와 모델들이 컨트롤러를 통해 연결되기 때문에 컨트롤러가 많은 책임을 가질 수 있다
    2. 코드 가독성이 떨어지기 때문에, 유지 보수와 확장을 어렵게 만든다

 

 


MVC 프로젝트의 폴더 구조

  • src
    • main
      • java
        •  com/example/demo
          • user
            • controller    # 컨트롤러
            • service        # 서비스
              • impl
            • model          # 모델
          • board
            • controller
            • service
              • impl
            • model
          • DemoApplication.java  # 스프링 부트 애플리케이션의 시작점
    • resources
      • mybtis
        • mapper
    • webapp
      • WEB-INF
        • views   # (User Interface)

 

폴더 구조는 정해진 것은 없기 때문에, 다양하게 구조화할 수 있다

모델 부분에서는 vo / dto / repository 패키지로도 구성할 수 있지만, 나는 model 패키지로 구성하려 한다

그리고 MyBatis / JPA 를 사용하는지에 따라서도 다르게 구성되는 것 같다

 


참고 링크

 

 

[Design Pattern] 1. MVC 패턴

디자인 패턴

jooncco.com

 

MVC(Model, View, Controller) Pattern

<br /><br />

junhyunny.github.io

 

'JAVA > Spring' 카테고리의 다른 글

[Springboot] MyBatis (feat. MySQL)  (1) 2023.09.11
[Springboot] Lombok  (0) 2023.09.04
[Springboot] 스프링부트 시작하기  (0) 2023.09.03

+ Recent posts