독까의 이야기

문제 1 (난이도 : 中)  
N 줄인 삼각형을 출력한다. 단, 사용자로 부터 임의의 N 을 입력 받는다. 아래는 N = 3 일 때의 출력 예시 이다.  

*    
**  
***

# 접근 1.
다른 강좌나 게시글을 보면, 출력 결과물에 대한 설명이 부족해서 이해가 잘 안갔다. 
수학을 가르치지만 프로그래밍은 다룬적 없는 와이프에게 수학적으로 설명을 해달라고 부탁했다.
와이프는 수식을 보고 수기로 풀어 보더니 금방 이해가 되었다고 했다. 
아이들에게 가르치는 방식으로 설명을 요청했다. 
별(*) 에 대한 개념을 수로 바꾸어서 표현하니 이해가 쉬웠다. 

#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = 1; j <= i; j++)
                     printf("*");
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = 1; j <= i; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
몇 줄 짜리 삼각형? : 5
i = 1 :  *
i = 2 :  **
i = 3 :  ***
i = 4 :  ****
i = 5 :  *****
최종 i 값 = 6
몇 줄 짜리 삼각형? : 5
i = 1 :  1
i = 2 :  12
i = 3 :  123
i = 4 :  1234
i = 5 :  12345
최종 i 값 = 6


#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = input; i >= 1; i--)
       {
              printf("i = %d :  ", i);
              for (j = 1; j <= i; j++)
                     printf("*");
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = input; i >= 1; i--)
       {
              printf("i = %d :  ", i);
              for (j = 1; j <= i; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
몇 줄 짜리 삼각형? : 5
i = 5 :  *****
i = 4 :  ****
i = 3 :  ***
i = 2 :  **
i = 1 :  *
최종 i 값 = 0
몇 줄 짜리 삼각형? : 5
i = 5 :  12345
i = 4 :  1234
i = 3 :  123
i = 2 :  12
i = 1 :  1
최종 i 값 = 0
위 두 수식의 차이점은 
for (i = 1; i <= input; i++)    /    for (i = input; i >= 1; i--)
외에는 없다. 
위에서 아래로 늘어나는 삼각형을 역순으로 만들려면 적용 방식을 역순으로 하면 된다. 

이렇게 설명을 해주었으면 좋았을 텐데, 강좌나 게시들에서는 "문제, 답" 이렇게만 적어놔서 조금 아쉽다. 


# 접근 2.
우측 정렬 된 삼각형을 만들어보자. 

#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = input; i >= 1; i--)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j <= i; j++)
                     printf("*");
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = input; i >= 1; i--)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j <= i; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = input; i >= 1; i--)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf("%d", j);
              for (j = 1; j <= i; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
몇 줄 짜리 삼각형? : 5
i = 5 :  *****
i = 4 :   ****
i = 3 :    ***
i = 2 :     **
i = 1 :      *
최종 i 값 = 0
몇 줄 짜리 삼각형? : 5
i = 5 :  12345
i = 4 :   1234
i = 3 :    123
i = 2 :     12
i = 1 :      1
최종 i 값 = 0
몇 줄 짜리 삼각형? : 5
i = 5 :  12345
i = 4 :  51234
i = 3 :  54123
i = 2 :  54312
i = 1 :  54321
최종 i 값 = 0


#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j <= i; j++)
                     printf("*");
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j <= i; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf("%d", j);
              for (j = 1; j <= i; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
몇 줄 짜리 삼각형? : 5
i = 1 :      *
i = 2 :     **
i = 3 :    ***
i = 4 :   ****
i = 5 :  *****
최종 i 값 = 6
몇 줄 짜리 삼각형? : 5
i = 1 :      1
i = 2 :     12
i = 3 :    123
i = 4 :   1234
i = 5 :  12345
최종 i 값 = 6
몇 줄 짜리 삼각형? : 5
i = 1 :  54321
i = 2 :  54312
i = 3 :  54123
i = 4 :  51234
i = 5 :  12345
최종 i 값 = 6


# 접근 3.
피라미드형 삼각형을 만들어보자.

#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j < i * 2; j++)
                     printf("*");
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j < i * 2; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf("%d", j);
              for (j = 1; j < i * 2; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
몇 줄 짜리 삼각형? : 5
i = 1 :      *
i = 2 :     ***
i = 3 :    *****
i = 4 :   *******
i = 5 :  *********
최종 i 값 = 6
몇 줄 짜리 삼각형? : 5
i = 1 :      1
i = 2 :     123
i = 3 :    12345
i = 4 :   1234567
i = 5 :  123456789
최종 i 값 = 6
몇 줄 짜리 삼각형? : 5
i = 1 :  54321
i = 2 :  543123
i = 3 :  5412345
i = 4 :  51234567
i = 5 :  123456789
최종 i 값 = 6

#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = input; i >= 1; i--)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j < i * 2; j++)
                     printf("*");
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = input; i >= 1; i--)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j < i * 2; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
#include <stdio.h>
int main() {
       int i, j, input;
       printf("몇 줄 짜리 삼각형? : ");
       scanf_s("%d", &input);
       for (i = input; i >= 1; i--)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf("%d", j);
              for (j = 1; j < i * 2; j++)
                     printf("%d", j);
              printf("\n");
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
몇 줄 짜리 삼각형? : 5
i = 5 :  *********
i = 4 :   *******
i = 3 :    *****
i = 2 :     ***
i = 1 :      *
최종 i 값 = 0
몇 줄 짜리 삼각형? : 5
i = 5 :  123456789
i = 4 :   1234567
i = 3 :    12345
i = 2 :     123
i = 1 :      1
최종 i 값 = 0
몇 줄 짜리 삼각형? : 5
i = 5 :  123456789
i = 4 :  51234567
i = 3 :  5412345
i = 2 :  543123
i = 1 :  54321
최종 i 값 = 0


# 접근 4.
다이아몬드 형태를 만들어 보자. 
정방향과 역방향을 합치고 중복되는 정가운데를 상쇄하면 될 것 같다. 

int main() {
       int i, j, input;
       printf("가장 긴 행의 수 입력 : ");
       scanf_s("%d", &input);
       for (i = 1; i <= input; i++)
       {
              printf("i = %d :  ", i);
              for (j = input; j > i; j--)
                     printf(" ");
              for (j = 1; j < i * 2; j++)
                     printf("*");
              printf("\n");
              if (i == input) {
                     for (i = input - 1; i >= 1; i--)
                     {
                           printf("i = %d :  ", i);
                           for (j = input; j > i; j--)
                                  printf(" ");
                           for (j = 1; j < i * 2; j++)
                                  printf("*");
                           printf("\n");
                     }
                     break; // 조건 완료시 중지를 하지 않으면 무한루프 발생
              }
       }
       printf("최종 i 값 = %d", i);
       return 0;
}
가장 긴 행의 수 입력 : 5
i = 1 :      *
i = 2 :     ***
i = 3 :    *****
i = 4 :   *******
i = 5 :  *********
i = 4 :   *******
i = 3 :    *****
i = 2 :     ***
i = 1 :      *
최종 i 값 = 0


MS-SQL 2008 ENT 이상 버전에서 지원되는 TDE 기능에 대한 테스트를 진행 한다. 
STD 에서도 복원은 가능하나, DB 는 사용 할 수 없다. 

OS : Windows 2016
DBMS : MS-SQL 2014 ENT

1. DB 생성
DB 명 : gunnm 
USE master;
CREATE DATABASE [gunnm]
ON
( NAME = gunnm, FILENAME = 'D:\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\gunnm.mdf')
LOG ON
( NAME = gunnm_log, FILENAME = 'D:\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\gunnm_log.ldf')
GO




2. 암호화 진행

마스터 키 생성
USE master
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'PassWord!2#'
GO

마스터 키로 보호 된 인증서 생성
CREATE CERTIFICATE gunnm_cert WITH SUBJECT = 'gunnm_cert'
GO

마스터 키 백업
USE master
BACKUP SERVICE MASTER KEY TO FILE = 'H:\service_master.key' ENCRYPTION BY PASSWORD = 'Service_PW@1119'
GO
BACKUP MASTER KEY TO FILE = 'H:\db_master.key' ENCRYPTION BY PASSWORD = 'DB_PW#1119'
GO

DB 암호화 키 생성
USE gunnm
GO
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER CERTIFICATE gunnm_cert 
GO

실행 메시지 
경고: 데이터베이스 암호화 키를 암호화하는 데 사용된 인증서가 백업되지 않았습니다. 인증서와 인증서에 연결된 개인 키를 즉시 백업해야 합니다. 인증서를 사용할 수 없게 되거나 다른 서버에서 데이터베이스를 복원하거나 연결해야 할 경우 인증서와 개인 키의 백업본이 있어야 합니다. 그렇지 않으면 데이터베이스를 열 수 없습니다.

DB 암호화 적용
USE gunnm
GO
ALTER DATABASE gunnm
SET ENCRYPTION ON
GO

DB 암호화 키 백업
USE master
BACKUP CERTIFICATE gunnm_cert TO FILE = 'H:\gunnm_cert.cer' WITH PRIVATE KEY ( FILE = 'H:\gunnm_cert.pvk' , ENCRYPTION BY PASSWORD = 'gunnm_PW$1119' )
GO

DB 백업
BACKUP DATABASE [gunnm] TO  DISK = 'H:\gunnm.bak';
GO



3. 대상 서버에서 DB 복원 진행

원본 서버에서 생성 된 DB 인증서 파일 (.cer / .pvk) 및 DB 백업 파일 (.bak) 을 복사한다. 

마스터 키 생성 : 원본 서버와 동일한 패스워드를 입력할 필요는 없다. 
USE master
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'PassWord1@3'
GO
CREATE CERTIFICATE gunnm_cert WITH SUBJECT = 'DB_Enc'
GO

원본 서버 인증서 파일을 통한 인증서 생성 및 DB 복원
CREATE CERTIFICATE gunnm_cert
  FROM FILE = 'H:\gunnm_cert.cer'
  WITH PRIVATE KEY ( 
    FILE = 'H:\gunnm_cert.pvk',
 DECRYPTION BY PASSWORD = 'gunnm_PW$1119'
  );

실행 메시지 : 
메시지 15232, 수준 16, 상태 1, 줄 2
이름이 'gunnm_cert'인 인증서가 이미 있거나 이 인증서가 데이터베이스에 이미 추가되었습니다.
테스트이므로 서버간 이동을 하지 않고, 동일 서버에서 진행되어 발생 된 오류로 추정

-- 등록 인증서 제거
USE master; 
DROP CERTIFICATE gunnm_cert;


CREATE CERTIFICATE gunnm_cert
  FROM FILE = 'H:\gunnm_cert.cer'
  WITH PRIVATE KEY ( 
    FILE = 'H:\gunnm_cert.pvk',
 DECRYPTION BY PASSWORD = 'gunnm_PW$1119'
  );

RESTORE DATABASE [gunnm]
  FROM DISK = 'H:\gunnm.bak'
  WITH MOVE 'gunnm' TO 'D:\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\gunnm.mdf',
       MOVE 'gunnm_log' TO 'D:\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\gunnm_log.ldf';
 



4. TDE 모니터링 스크립트
SELECT DB_NAME(database_id) AS DatabaseName, encryption_state,
encryption_state_desc =
CASE encryption_state
         WHEN '0'  THEN  'No database encryption key present, no encryption'
         WHEN '1'  THEN  'Unencrypted'
         WHEN '2'  THEN  'Encryption in progress'
         WHEN '3'  THEN  'Encrypted'
         WHEN '4'  THEN  'Key change in progress'
         WHEN '5'  THEN  'Decryption in progress'
         WHEN '6'  THEN  'Protection change in progress (The certificate or asymmetric key that is encrypting the database encryption key is being changed.)'
         ELSE 'No Status'
         END,
percent_complete,encryptor_thumbprint, encryptor_type  FROM sys.dm_database_encryption_keys 


USE master
GO
SELECT * FROM sys.certificates

-- encryption_state = 5 is encrypted
SELECT * FROM sys.dm_database_encryption_keys
WHERE encryption_state = 3; 



5. 암호화 제거

DB 암호화 비활성화
USE gunnm
ALTER DATABASE gunnm SET ENCRYPTION OFF
GO

DB 암호화 키 제거
USE gunnm
GO
DROP DATABASE ENCRYPTION KEY  

마스터 키 및 인증서 제거
-- 마스터 키 제거
USE master;
drop master key;
GO

-- 등록 인증서 제거
USE master; 
DROP CERTIFICATE gunnm_cert;
GO  



요즘 대부분의 웹사이트들은 보안 인증서 (SSL) 적용이 되어 있다. 개인 정보가 등록되어 있는 웹사이트들은 SSL 미적용시 법적으로 처벌을 받게 되어 있다. 


https 프로토콜의 기본 포트는 443 이다. 

443 포트를 다수의 웹사이트가 공유하여 사용하려면, 멀티 인증서 또는 와일드카드 인증서를 적용해야만 했다. 

그러나, IIS 8.0 이상 부터는 동일 아이피에서도 443 포트 다중 사용이 가능하게 되었다. 


https://docs.microsoft.com/en-us/iis/get-started/whats-new-in-iis-8/iis-80-server-name-indication-sni-ssl-scalability


"서버 이름 표시" SNI 가 그것인데, 해당 기능에 대해서 테스트를 진행하도록 하겠다. 



# 1 

SSL 적용 될 웹사이트 생성 


sni1.gunnm.xyz 

sni2.gunnm.xyz




# 2 

발급 된 인증서 가져오기

30일 무료 이용 가능한 인증서 발급 받은 후 진행 했다. 


IIS 최상단 노드에서 "서버 인증서" 선택


우측 상단 "가져오기" 선택해서 발급 받은 .pfx 인증서를 선택한다. 

인증서 저장소는 "웹 호스팅" 으로 지정한다. 개인으로 선택해도 되는데, 기술문서에서 웹 호스팅으로 선택 했다고 하니깐 그대로 따라해 본다. 



sni2.gunnm.xyz 인증서도 동일한 방식으로 가져온다. 


완료시 아래와 같이 확인 가능하다. 




# 3

바인딩에 https 프로토콜 추가


호스트 이름은 반드시 CN 과 동일하게 입력한다. 


ex) 

기존 등록 된 바인딩 : gunnm.xyz / www.gunnm.xyz


SNI 설정시 https 프로토콜 2개 추가 필요

https://gunnm.xyz

https://www.gunnm.xyz






# 4

https 페이지 호출 및 SSL 바인딩 목록 확인





cmd 실행 후, netsh http show sslcert 입력




SSL 바인딩 조회시, 아이피에 대한 443 할당이 아닌 (127.0.0.1:443) 각 호스트값에 443 포트가 할당 된 것을 확인 할 수 있다. 


다수의 웹사이트를 구동 중인 사용자에게 유용한 기능이라고 할 수 있다.