블로그 이미지
자유로운설탕

calendar

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 31

Notice

2017. 2. 25. 21:55 프로그래밍

  이젠 4교시 때 정리한 mssql 코드와 5교시 때 정리한 암호화 코드를 이용해서 최종 기능을 만들어 보자.

 

[목차]

0. 왜 파이썬 공부에 구글을 이용하는게 좋은가?

1. 언어를 바라보는 방법. 파이썬을 어떻게 바라봐야 할까?

2. 파이썬 설치와 환경, 버전 선택 하기의 이유.

3. 만들고자 하는 기능을 모르는 조각으로 나눠 조사해 보기

4. 데이터 베이스에서 내용 가져와 출력하기

5. 암호화 모듈을 이용해 암복호화 해보기

6. 퍼즐 조각들을 합쳐보기

7. 엑셀 파일 사용해 보기 -> 부록 : fuction 을 이용해서, 코드 정리해 보기

8. 정규표현식을 왜 사용해야 할까? 언어속의 미니 언어 정규표현식 살펴보기

9. 입력과 결과를 GUI 화면과 연결해 보기

10. Whois API 이용해 보기

11. 웹페이지 호출해 내용 파싱 하기(BeautifulSoup 그리고 한계)

12. 자동화 - 웹 자동화(with Selenium)

13. 자동화 - 윈도우즈 GUI 자동화(with pywinauto)

14. 자동화 - 작업 자동화

15. 수학 라이브러리 살펴보기

16. 그래픽 라이브러리 살펴보기

17. 머신러닝에서의 파이썬의 역활

18. 웹 프로그래밍 - Legacy Web

19. 웹 프로그래밍 - Flask 살펴보기(feat. d3.js)

20. 웹 프로그래밍 - Django 살펴보기

21. 정리 - 이런저런 이야기

 

 

 

[들어가면서]

  최종 기능은 테이블에 저장된 평문 문자열을 암호화 한 후 복호화 해서 각각 테이블 내 다른 필드에 저장하고, 이후 전체 내용을 조회해 잘 암,복호화 됬다는 증거로 화면에 표시한다. 그림으로 표시하면 아래와 같다.

 

 

 

[테이블과 원본 데이터 생성]

  일단 테이블을 하나 만든다. 4교시때 만든 'mytest' db에 저장하고, 만약 테이블 생성 하는 부분이 가물가물 하다면, 4교시에 자세하게 설명해 놓았으니 참고하여 생성한다.

1
2
3
4
5
CREATE TABLE [dbo].[play](
    [original] [char](30) NULL,
    [encrypted] [char](200) NULL,
    [decrypted] [char](30) NULL,
)
cs

 

  이후 위의 그림의 A 값을 하나 넣는다.

1
insert play values('secret','','')
cs

 

  내용을 한번 조회해 본다.

1
select * from play(nolock)
cs

 

  아래와 같이 original 에만 우리가 넣은 secret 라는 단어가 들어가 있다. 나머지 2개는 파이썬이 채워줄 예정이다.

 

 

 

[업데이트 쿼리 만들기]

  4, 5교시때 진행한 내용을 되돌아 보면 현재 우리가 모르고 있는 부분 하나는 테이블의 encrypted, decrypted 필드에 원하는 값을 업데이트를 하는 것이다. DB는 복잡하게 보면 많이 복잡하지만 단순하게 보면 파일과 비슷한 면이 있다.(사실 DB는 파일에 저장하는 것을 좀 더 구조적으로 저장하여, 상호 관계를 분석하거나 빠르게 결과를 찾기 위해 만들어진 구조화된 파일 이라고 봐도 될 듯하다.) 파일에 할수 있는 일이 생성(create), 수정(update), 내용, 파일 삭제(delete), 읽기(read) 이 듯, DB안에 들어가 있는 테이블에 할 수 있는 작업도 역시 이 4가지다. 그래서 좀 이 4개의 행동들의 앞 자리들을 따서 조금 고상하게 CRUD 라고 표현하기도 한다. 그럼 4교시때 select 하는 부분은 배웠는데, update 하는 내용은 배우지 않았으니 update 하는 부분을 구글을 통해 찾아보려 한다.

 

  구글에서  'mssql update' 로 검색한다. 한글로 잘 정리된 페이지를 참조해도 좋고, 이전 시간에도 참고했던 아래 techonthenet 페이지를 보자(개인적으로 깔끔하게 핵심만 정리한듯 하여...)

https://www.techonthenet.com/sql_server/update.php

 

  간단히 설명하면 아래와 같다.

1
2
3
4
5
6
UPDATE 테이블
SET 컬럼1 = '값1',
    컬럼2 = '값2' ....
WHERE 컬럼x = '값3';
-- 테이블을 업데이트 하는데, 특정 컬럼에 값3이 들어있는 행을 찾아서, 
-- 컬럼1,2를 새로운 값으로 채운다.
cs

 

  해당 문법을 참조하여 좀 전에 만든 테이블 구조를 업데이트 하는 쿼리를 만들면 아래와 같다.

1
2
3
4
5
-- secret 가 저장된 행을 찾아서 encrypted 컬럼을 암호화된 값으로 업데이트 한다.
update play set encrypted = '암호화 값' where original='secret'
 
-- secret 가 저장된 행을 찾아서 decrypted 컬럼을 복호화된 값으로 업데이트 한다.
update play set decrypted = '복호화 값' where original='secret'
cs

 

 

  해당 코드를 이전 시간의 암호화 한 함수 코드를 호출하는 방식으로 만들면 아래와 같이 된다.

1
2
3
4
5
6
7
8
9
10
# original 필드 조회한다
cursor.execute('SELECT original FROM play(nolock);')
row = cursor.fetchone()
original = str(row[0])
# 암호화 한다.
encrypted = AESCipher(key).encrypt(original)
 
# 암호화한 값 encrypted 필드에 업데이트 한다.
cursor.execute("update play set encrypted = %s where original='secret'", encrypted)
conn.commit()
cs

 

 

  해당 코드를 복호화 한 함수를 호출하는 방식으로 합쳐서 만들면 아래와 같이 된다.

1
2
3
4
5
6
7
8
9
10
# encrypted 필드 조회한다
cursor.execute('SELECT encrypted FROM play(nolock);')
row = cursor.fetchone()
encrypted_select = str(row[0])
# 복호화 한다
decrypted_insert = AESCipher(key).decrypt(encrypted_select)
 
# 복호화 한 값 decrypted 필드에 업데이트 한다.
cursor.execute("update play set decrypted = %s where original='secret'", decrypted_insert)
conn.commit()
cs

 

 

  전체를 조회하는 쿼리는 SQL 샘플과 비슷하지만, 줄 바꿈을 위해 약간 보기 좋게 하기 위해서 문자열 더하기 연산자와(+), 문자열 좌우의 빈 공간을 지우는 함수(strip)를 이용하여 보기좋게 정렬하려 한다. 해당 코드는 아래와 같다.

1
2
3
4
5
6
7
# 모두 조회해서 줄로 나누어('\n') 출력한다. strip() 함수는 양쪽의 공백을 없애준다.
cursor.execute('SELECT * FROM play(nolock);')
row = cursor.fetchone()
while row:
  print ('original  : ' + str(row[0]) + "\n" + 'encrypted : ' 
  + str(row[1]).strip() + "\n" + 'decrypted : ' + str(row[2]))   
  row = cursor.fetchone()
cs

 

 

 

[전체 코드 조합하기]

  그럼 좀 길어 지지만 앞의 암복호화 함수와 합치게 되면 아래와 같이 된다. 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#-*- coding: utf-8 -*-
# 암호화 코드 출처: http://blog.dokenzy.com/
 
import pymssql
import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
 
# 아마 특정한 블록 사이즈를 채우기 위해서 입력된 값을 임의의 값으로 패딩(채워주기) 하는 코드 인 듯...
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS).encode()
unpad = lambda s: s[:-ord(s[len(s)-1:])]
 
# 초기화 코드 인듯
def iv():
    return chr(0* 16
 
# 2교시때 설명했 듯이 클래스는 구조를 잘 잡아주는 껍데기 이다.
class AESCipher(object):
 
    def __init__(self, key):
        self.key = key
 
    # 메시지를 암호화 하는 함수 
    def encrypt(self, message):
        message = message.encode()
        raw = pad(message)
        cipher = AES.new(self.key, AES.MODE_CBC, iv())
        enc = cipher.encrypt(raw)
        return base64.b64encode(enc).decode('utf-8')
    
    # 메시지를 복호화 하는 함수
    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        cipher = AES.new(self.key, AES.MODE_CBC, iv())
        dec = cipher.decrypt(enc)
        return unpad(dec).decode('utf-8')
 
# 암호화 키 
key = 'abcdefghijklmnopqrstuvwxyz123456'
 
 
# 커넥션 만들기
conn = pymssql.connect(server='localhost', user='pyuser', password='test1234', database='mytest')
cursor = conn.cursor()
 
# original 필드 조회한다
cursor.execute('SELECT original FROM play(nolock);')
row = cursor.fetchone()
original = str(row[0])
# 암호화 한다.
encrypted = AESCipher(key).encrypt(original)
 
# 암호화한 값 encrypted 필드에 업데이트 하기
cursor.execute("update play set encrypted = %s where original='secret'", encrypted)
conn.commit()
 
# encrypted 필드 조회한다
cursor.execute('SELECT encrypted FROM play(nolock);')
row = cursor.fetchone()
encrypted_select = str(row[0])
# 복호화 한다
decrypted_insert = AESCipher(key).decrypt(encrypted_select)
 
# 복호화 한 값 decrypted 필드에 업데이트 하기
cursor.execute("update play set decrypted = %s where original='secret'", decrypted_insert)
conn.commit()
 
# 모두 조회해서 줄로 나누어('\n') 출력한다. strip() 함수는 양쪽의 공백을 없애준다.
cursor.execute('SELECT * FROM play(nolock);')
row = cursor.fetchone()
while row:
  print ('original  : ' + str(row[0]) + "\n" + 'encrypted : ' 
  + str(row[1]).strip() + "\n" + 'decrypted : ' + str(row[2]))   
  row = cursor.fetchone()
cs

 

  위의 최종 소스를 긁어 c:\python\code 디렉토리에 mix_version.py 라고 파일을 만들고 실행 한다. (역시 실행 방법을 잘 모르겠으면 2교시를 참고한다). 아래와 같이 DB 에 저장 후 필드를 읽어와 화면에 가지런히 표시된다.

c:\Python\code>python mix_version.py
original  : secret
encrypted : F8/7UoVxGVoOxNdlo/0sbf/whobfIAoSVe3QvcbgehI=
decrypted : secret

 

 

 

[디버깅 및 리셋]

  직접 만들어 보는 경우는 중간 중간에 print 문을 통해 변수를 출력하여(물론 리스트와 같은 복합 자료형은 원하는 값을 출력하는 방법에 익숙해야 한다) 해당 값이 정확히 나오는지 확인 해 보는 것이 좋다. 아니면 pycharm 같은 IDE 툴의 디버깅 기능을 이용해도 될 듯 하다. 구글에서 'pycharm 디버깅' 이라고 치면 많은 블로그가 나온다. (뭐 하지만 여러 디버깅 책 들에서 얘기하듯이 디버깅은 머리속으로 구조적으로 하는 거고, print 나 디버깅 기능은 생각한 가설이 맞는지 실제 검증 할때 쓰는 것이라는 것을 잊으면 안된다). 테스트 도중 값을 리셋하기 위해 쓸 수 있는 쿼리를 아래 명시 하였다.(original 값만 빼고 나머지 두 값을 지워준다)

1
2
update play set encrypted ='', decrypted = ''
where original = 'secret'
cs

 

 

 

 

[Database 타입에 대한  간략 브리핑]

  마무리 하기 전에 앞 시간에서 여기서 정리한다고 했으니 database 에 대해 잘 모르는 사람들을 위해 요즘 회자되고 있는 여러가지 database 에 대해서 희미하게 아는 지식으로 간단히 분류하려 한다. 보통 많이 듣는 DB가 관계형 디비인 oracle, mssql, mysql, mariadb, postgreSQL, 빅데이터 라고 부르는 hBase, hive 등, 위치가 조금은 애매한 도큐먼트 디비인 mongodb, 그리고 메모리 디비라고 부르는 redis, elastic search 같은 애들이 있다. 

 

  첫번째 관계형 디비는 보통 ansi-sql 이라는 표준을 따르고 있으나, 각자 자체적으로 확장한 문법들이 많아서 한 SQL 제품에 맞는 쿼리를 다른 쪽에 던지면 보통 미세한 차이땜에 에러가 날 수 있지만, 몇 가지 제품에 쿼리들을 날려보다 보면 큰 틀에서 비슷비슷하다는 생각은 든다.(오히려 많이 차이가 나는 부분은 여러 관리 측면의 부분들이다) 관계형 디비의 장점은 관계의 꽃이라고 할 수 있는 join 기능을 통해 데이터 들 간의 관계를 쉽게 조회할 수 있다는 부분이 있지만 성능 문제 때문에 보통 하나의 서버 안에서만 join 이 가능하다고 보면 된다. 하나의 서버에 데이터를 모두 저장하기 때문에 응답 속도가 빠르지만, 데이터 양이 커지면 서버 용량이 모자라거나 메모리, cpu 에 부하가 걸리는 일도 생길 수 있다. NoSQL 이 나오기 전에 DB 계를 제패했었고 지금도 여전히 빅데이터와는 다른 특성의 데이터 영역들에서 잘 살고 있다고 본다. 참고로 mariadb는 오픈소스였던 mysql이 오라클에 넘어가게 되면서, 호환되는 오픈소스로 갈라진 버전이다. 두 개가 쿼리는 완전 동일했는데 현재는 서로 얼마나 차이가 나는진 잘 모르겠다. 

 

  NoSQL 에서 빅데이터 쪽은 보통 하둡(hadoop)이라는 여러 서버에 데이터를 나눠 보관할 수 있는 hdfs 란 파일 시스템을 기본으로 하는 hbase 디비가 있다. 해당 방식의 장점은 하나의 서버에서 지지고 볶는 관계형 디비와 달리, 토렌토나 컴퓨터들의 파워를 조금씩 나눠 쓰는 여러가지 그리드 형태의 서비스 처럼, 해야될 일을 분산되어 있는 데이터를 저장하고 있는 서버들에게 나눠 주어서 일을 시킨 후, 다시 결과를 모아서 보여줄 수 있는데 장점이 있는 듯하다. 많은 서버가 동시에 일을 나눠 하는 것이 가능해, 용량이 큰 데이터에 대해서 관계형 디비에 비해서 연산하기가 유리하기 때문에 Big데이터용 디비라고 불리는 것 같다. 이러한 분산 작업과 관련되어 맵, 리듀스, 셔플 같은 개념들이 쓰인다. 해당 데이터의 처리 과정이나 결과가 하둡 오리지날 방식에서는 비교적 복잡한 과정을 사용자가 직접 디자인해 줘야 하기 때문에, 해당 부분을 관계형 디비에서 사용하는 방식으로 커버를 씌워 준 것이, Hive(SQL 처럼 작업을 지시) 라고 보면 된다. Hive를 통하면 하둡에 적재된 데이터에 대해서 join 같은 형태의 관계형 작업의 에뮬레이션을 쉽게 지시할 수 있다. 개인적으로 이쪽은 명확히 이해는 못하고 있다고 생각하기 때문에, 아래 링크를 마지막으로 빅데이터 얘기를 마무리한다.

http://blog.acronym.co.kr/312

 

  Mongo 디비는 도규먼트 형식의 대표적인 디비로, 안에 json 형태의 문서를 담을 수 있다. 무엇 보다도 장점인 것 중 하나는 관계형 디비 같은 경우 입력되는 필드가 추가되면 alter table 을 통해 컬럼을 만들거나 수정해 맞춰주지 않으면 에러가 발생하지만(보통 스키마 변경이라고 한다. 컬럼 타입이나 갯수가 변경되면 스키마가 같이 변경되어 줘야 한다.), mongo 디비 같은 NoSQL 은 데이터의 변화에 따라 알아서 스키마를 고무줄 같이 조정하며 맞춰 주어서, DBA의 스키마 관리 역활이 사실 좀 모호해지는 듯 싶다. 그래서 비교적 어플리케이션의 쿼리 호출을 막 바꿀 수 있어 보통 개발자 들한테 인기가 많은 듯도 싶다. 비슷한 타입의 대체 가능한 디비가 뭐가 있는지는 잘 모르겠다.

 

  메모리 디비는 일단 가능한 많은 데이터들을 메모리에 올려 놓는 구조이다. 가능한 많은 데이터를 메모리에 올려 놓고 조회하는 구조로 쿼리에 대해 빠른 응답이 필요한 경우 사용하는 듯 하다. redis 는 키, 밸류 방식의 메모리 디비이다.

 

  Elastic search 디비와 검색엔진이 합쳐진 형태로 대용량 로그 검색이나 검색 엔진 등에서 주로 사용되는 듯하다. 

 

  여담이지만 오픈소스는 사용 비용은 무료지만 보통 통합 관리나, 성능 관리, 보안 등의 기능이 약한 경우가 있어, 그런 부분을 커스터마이즈 하여 확장한 관련 솔루션을 추가로 구입해(외국엔 그런 걸로 잘 사업하며 먹고 사는 기업들도 많은 듯한다) 사용해야 하는 경우도 많기 때문에, 결국 유지 비용이 비슷비슷해지는 경우도 종종 있다고 한다.

 

  그럼 요 정도로 디비 종류 얘기는 마무리하고 혹 잘몰라서 잘못된 얘기를 했더라도 넓은 맘으로 이해해 주길 바라며 글을 마친다.

 

 

 

1
2017.2.25 by 자유로운설탕
cs

 

 

 

posted by 자유로운설탕