해시(Hash) 함수 이야기






"md5 해시값을 복호화하는 사이트에서 5초도 안 걸려 계정정보가 복호화가 되는 것을 확인했다."


"사태 초기엔 이용자 650만 명의 계정과 SHA-1 알고리즘 기반 비밀번호 해시값이 유출됐다고 알려졌지만

실제 계정정보 유출 피해 규모는 1억1천700만 명 이상이라는 사실이 지난 5월 추가로 확인됐다."


“당사는 비밀번호를 평문으로 저장하지 않는다방향 해시를 사용한다고 설명했다. 

일방향 해시를 사용할 경우 무작위 대입 공격만이 유일한 복호화 방법으로

이는 시간도 많이 들고 따라서 비용이 크게 올라간다고 강조하며 고객들을 안심시켰다."




인터넷에서 보안 관련 뉴스를 보면 패스워드 유출 사건 기사에 '해시값', 'MD5', 'SHA-1', 'SHA-256' 등 해시 함수와 관련된 단어를 종종 볼 수 있습니다.


한창 뜨거웠다가 요즘은 잠잠해진거 같은 비트코인에서도 해시 함수를 사용하는데 관심이 있다면 이참에 개념을 잡는 데 도움이 되었으면 좋겠습니다.


그럼 해시 함수가 무엇인가에 관해 이야기해보겠습니다.



1. 해시 함수란?


명절 때 뉴스에서 한 번쯤 보았을 법한 떡방앗간에서 가래떡을 뽑는 기계를 생각해봅시다.


기계의 윗부분에 커다란 떡 반죽 덩어리를 올려놓으면 밑으로 가래떡이 길게 늘어져 나오며


일정한 길이가 되면 잘라서 상자에 담는 장면을 본 적이 있을 겁니다.


해시 함수란 이 가래떡을 뽑는 기계와 같은 역할을 하고 있습니다.


다만, 떡을 뽑는 게 아니라 해시 함수에 데이터를 넣으면 일정한 길이의 문자열들이 나오게 됩니다.


또한 기계의 종류가 여러 모델이 있듯이 해시 함수에도 여러 종류가 있습니다.


대표적으로 MD5, SHA-1, SHA-256 등이 있습니다.


각 해시 함수가 어떻게 동작하는지는 여기서는 설명을 생략하고 이런 종류가 있다는 것만 알면 되겠습니다.



2. 해시 함수는 어디에 사용할까?


주로 파일을 내려받았을 때 정상적으로 파일이 다운로드 되었는지 확인하는 용도로 사용하거나 


데이터베이스에 패스워드를 저장할 때 사용 할 수 있습니다.


그밖에도 필요한 곳 어디든 사용할 수 있습니다.


먼저 내려받은 파일을 확인하는 경우를 살펴보겠습니다.


파일을 제공하는 서버는 파일과 그 파일의 해시값을 같이 제공합니다.


사용자는 파일을 내려받은 후에 파일을 해시 함수에 집어넣어서 나온 해시값과 비교해봅니다.


해시값이 같다면 정상적으로 파일을 내려받은 것이고 다르다면 중간에 파일이 깨졌거나 잘못된 파일을 내려받은 것이 됩니다.


위에서 얘기했지만, 파일도 데이터이므로 충분히 해시 함수에 넣을 수 있습니다.


다음으로 패스워드를 저장할 때를 살펴보겠습니다.


패스워드를 그대로 데이터베이스에 저장했다가 데이터베이스가 유출될 경우


아이디 / 패스워드 쌍이 그대로 해커의 손에 넘어가 다른 서비스에서 로그인 시도를 해보는 등 2차 피해를 유발할 수 있습니다.


따라서, 데이터베이스가 유출되더라도 패스워드를 알지 못하도록 하려고 패스워드를 해시 함수에 넣어서 나온 해시값을 저장합니다.



3. 해시 함수는 암호화의 방법일까?


블로그나 뉴스 기사를 보면 해시 함수를 암호화와 동일하게 취급하는 글이 종종 보입니다.


엄밀히 말하면 해시 함수와 암호화는 같은 개념이 아닙니다.


해시 함수는 단방향(일방향)으로서 해시 함수를 통해 나온 문자열 값에서 원래의 데이터로 복원할 수 없습니다.


암호화는 비밀키가 있다면 복호화를 통해 암호화된 값에서 원래의 데이터로 복원할 수 있습니다.


일반적으로 해시 함수를 통해 나온 값을 패스워드로 사용함으로써 눈으로 봐서는 값을 알 수 없기 때문에 암호화라고 얘기하지만 사실은 난독화에 가깝습니다.



4. 해시 함수는 복호화가 가능한가?


위에서 얘기했듯이 해시 함수는 단방향으로서 원래의 데이터로 복원할 수 없다고 했습니다.


하지만 인터넷에서 조금만 찾아보면 MD5, SHA-1을 복호화해준다고 하는 사이트가 많습니다.


이런 곳에서는 어떻게 원본 데이터를 복원해준다고 하는 것일까요?


원칙적으로는 원래의 데이터로 복원할 수 없기 때문에 이런 곳에서는 해시 함수를 통과하게 하는 기능도 같이 제공합니다.


그래서 사용자가 해시 함수를 통과시키려고 시도하는 데이터와 출력으로 나온 해시값을 같이 데이터베이스에 저장합니다.


그럼 반대로 복호화를 시도하려고 하는 사람에게는 데이터베이스의 해시값을 조회해 같은 값이 있다면 원래의 데이터를 보여주는 방식입니다.


해커는 유출된 데이터베이스에서 얻은 해시값을 이런 온라인 복호화 사이트에서 조회해볼 수 있기 때문에


비밀번호로 주로 사용하는 문자열은 해시 함수 온라인 사이트를 이용하지 않는 것이 좋습니다.



시간이 지나면서 장비 성능의 발달로 취약점이 생기게 된 경우가 있습니다.


예를 들어 해시 함수의 결과물인 해시값으로 a,b,c 세 가지의 문자로 길이가 3인 문자열이 나온다고 가정해봅시다. (임의의 해시 함수 내부의 과정을 통해)


그럼 aaa, aab, aac, aba, abb, abc, aca, acb, acc, ... , caa, cab, ... , ccc 이렇게 총 27개의 경우의 수가 있습니다.


하지만 세상에는 데이터의 경우의 수가 무궁무진한데 해시값의 결과로 27개의 경우의 수밖에 없으니


아무래도 원본 데이터는 다르지만 해시값이 같은 경우가 발생합니다.


이런 현상을 충돌(Collision)이라고 합니다.


해시값으로는 원본을 복원할 수 없으니 원본을 바꾸어서 같은 해시값을 갖는 데이터를 찾는 방법입니다.


처음에 예를 들었던 비밀번호 저장에 취약한 해시 함수를 사용하는 것을 다시 생각해봅시다.


이 경우에는 기존에 저장되었던 비밀번호가 아닌 다른 비밀번호를 입력했지만 해시값이 같아 인증을 통과하게 됩니다.


따라서 좀 더 충돌이 생기지 않는 긴 해시값이 나오는 해시 함수를 사용하도록 권장되는 이유이기도 합니다.


비트(Bit), 바이트(Byte) 이야기









"비트코인의 비트는 무슨 뜻일까?"


"기가인터넷의 기가는 무슨 뜻까? 기가인터넷은 얼마나 빠른거지?"


"내 핸드폰 용량은 64기가야"


"우리집 하드디스크는 1테라야"





요즘 일상생활에서 어렵지 않게 데이터양을 나타내는 단어들을 접할 수 있습니다.


광고에서도 기가인터넷을 얘기하면서 빠르다고 광고를 하고 있지만 사실 얼마나 빠른지 와닿지 않는게 사실입니다.


핸드폰도 32기가, 64기가, 128기가 등으로 같은 기종의 용량이 다른 핸드폰을 판매하고 있지만 


사진, 동영상이 어느정도 더 저장된다는 것 말고는 잘 알지 못합니다.


이 모든 단어의 기본 단위가 되는 비트, 바이트에 대해서 알아보겠습니다.




1. '비트(Bit)'란 무엇일까?


비트는 간단히 말해 '단위'입니다. 물건을 세는 단위인 '개'와 같은 격입니다.


1개, 2개, 3개 세듯이 1비트, 2비트, 3비트 세는 것이죠.


비트는 물건을 세는 대신에 데이터를 세는 단위라고 보면 되겠습니다.


연필의 경우 연필 1개, 연필 2개, 연필 3개 세다가 12개가 되면 1다스라고 부릅니다.


데이터의 경우에는 1비트, 2비트, 3비트 세다가 8비트가 되면 1바이트라고 부릅니다.




2. '비트(Bit)'는 어디서 사용할까?


비트는 데이터를 다루는 모든 곳에서 사용할 수 있습니다.


근처에서 가장 쉽게 접할 수 있는 것은 바로 컴퓨터입니다.


우리가 아무생각 없이 브라우저를 켜고 키보드를 쳐서 검색을 할 때도 컴퓨터에게 하나하나 명령을 내립니다.


그럼 컴퓨터가 명령을 알아들어야 하는데 사람간에도 마찬가지이지만 말이 통하려면 언어가 서로 일치해야합니다.


컴퓨터가 제일 효과적으로 잘 알아들을 수 있는 언어는 이진수입니다.


이진수 숫자 1개는 0 또는 1을 나타내며 주로 전구에 많이 비유가 됩니다.


전구가 켜졌다면 1을 나타내고, 전구가 꺼졌다면 0을 나타냅니다.


전구도 꺼지거나 켜지거나 두가지 경우만 있듯이 이진수도 0 또는 1 두가지 경우만 있습니다.


위에서 얘기했듯이 비트는 데이터를 세는 단위를 나타내는데 이진수 1'개'를 1'비트'라고 합니다.


예를 들어, 10100101 라는 연속된 이진수 8개가 있다면 이건 8비트라고 하며 또는 1바이트라고 부릅니다.


이런 연속된 이진수를 컴퓨터가 제일 잘 이해하는 형태이고 사실 컴퓨터가 처리하는 데이터란 이진수의 연속입니다.


결국, 키보드를 치면 키보드에서 전달된 신호를 내부적으로 연속된 이진수 나열로 바꾸고 컴퓨터가 쉽게 처리하게 되는 것입니다.




3. '기가'는 얼마나 큰 걸까?


데이터양을 다루는 단위에도 크기에 따라 순서가 있는데 이걸 먼저 알아보고 기가바이트가 어느정도 큰 것인지 알아보겠습니다.


비트(b) -> 바이트(B) -> 킬로바이트(KB) -> 메가바이트(MB) -> 기가바이트(GB) -> 테라바이트(TB) -> 페타바이트(PB) -> 엑사바이트(EB)


비트 8개를 모아서(8비트) 1바이트라고 했지만 그 이후부터는 1024개씩 모아서 다음 단위로 넘어갑니다 (계산상의 편의 등을 위해 보통 1000개씩 묶기도 합니다)


즉, 바이트 1024개를 모으면(1024바이트) 1킬로바이트가 되는 것이고 1024킬로바이트를 모으면(1024킬로바이트) 1메가바이트가 됩니다.


흔히 1기가, 2기가라고 부르는 것은 1기가바이트, 2기가바이트를 줄여서 얘기하는 것입니다.


그렇다면 1기가바이트는 1024메가바이트이고


1024메가바이트는 1024 * 1024킬로바이트 (1메가바이트는 1024킬로바이트이기 때문에 1024 * 1024킬로바이트)


1024킬로바이트는 1024 * 1024바이트 (1킬로바이트는 1024바이트이기 때문에 1024 * 1024바이트)


따라서 1기가바이트는 1024 * 1024 * 1024바이트 = 1073741824바이트입니다.(약 10억바이트)



하드디스크가 1테라바이트라고 했을 때


사진 한 장에 1메가바이트라고 가정한다면 1기가바이트에는 사진 1024장을 저장할 수 있고


1테라바이트는 1024기가바이트이므로 1024 * 1024이니까 약 105만장 정도를 저장할 수 있는 용량입니다.


드라마 동영상의 경우는 한 편에 1기가바이트라고 가정한다면 1024편의 드라마를 저장할 수 있습니다.




4. '기가'는 얼마나 빠른 걸까?


다시 한번 얘기하지만 비트, 바이트는 데이터를 다루는 모든 곳에서 사용하기 때문에


용량 뿐만 아니라 속도에서도 사용할 수 있습니다.


주변에서 컴퓨터가 데이터를 처리하는 속도나 인터넷이 얼마나 빠른지 얘기할 때 쓰입니다.


데이터 처리 속도를 얘기하려면 무엇이 필요한지 생각해봅시다.


먼저 기준이 되는 시간이 있습니다. 1초에 얼마큼 처리했다, 1시간에 얼마큼 처리했다.


그럼 얼마큼에 해당하는 데이터 단위가 필요하겠습니다.


지금까지 얘기한 비트가 될 수 있겠죠?


자동차의 경우에 30km/h의 속도라고 하면 1시간에 30km를 가는 속도라는 뜻입니다.


데이터의 경우에는 bps(bit per second)를 이용해 30bps라고 하면 1초에 30비트를 전송하는 속도를 뜻합니다.



기가인터넷은 최소 초당 100메가비트(100Mbps)보다 더 많이 전송해야하고 최대 초당 1기가비트(1Gbps)를 전송할 수 있는 상품입니다.


억단위를 넘어가면서 숫자가 감이 안오는데 다시 드라마를 다운받는다고 생각해보겠습니다.


드라마 한 편에 1기가바이트라고 한다면 기가인터넷의 경우 1초보다 조금 더 지나면 다운로드가 완료되는 속도입니다. (최대 속도일때)


실제로는 항상 최대속도를 보장하지는 않기 때문에 그보다는 시간이 더 걸리겠습니다.

  1. 쵸파 블로그 2018.04.05 00:17 신고

  2. 아파트담보 2018.04.05 23:14 신고

    쉽게 잘 설명해 주셨네요 ~ . ^^ 구경 잘 하고 갑니당 . 이런 글 보면 예전에 삼국지 2하면서 이진법변환해서 장수들 능력치 바꿨던 기억이 ㅋㅋ

처음 배우는 데이터 과학



출처: http://www.hanbit.co.kr/



- 판매처(오름차순)

교보문고

도서11번가

반디앤루니스

알라딘

인터파크

yes24



- 저자

필드 케이디

- 역자

최근우

- 출판사

한빛미디어



- 읽으면서 든 어디까지나 주관적인 생각
1. 파이썬 코드로 예제가 작성되어 있어서 많은 사람들이 테스트해보기 좋을 것 같음
2. 데이터 과학에 처음 입문하는 사람들에게 추천
3. 데이터 과학, 머신러닝, 통계 등 헷갈릴 수 있는 부분에 대해 이해하기 쉽게 정리되어 있음
4. 번역이 깔끔하게 되어 있음
5. 몇몇 단어는 본래 영단어로 쓰는게 더 좋을거 같다는 생각(ex. 맷플롭립 -> matplotlib)
6. 방대한 목차에 비해 책이 두껍지 않기 때문에 많은 주제를 다루고 있지만 보다 심도있는 학습을 위해서는 다른 서적을 추가로 참조해야함
7. 파이썬 문법이나 프로그래밍 방법론 같은 주제는 데이터 과학에 있어 필요한 부분이긴 하나 약간 생뚱맞은 느낌


- 오탈자(초판 1쇄 기준)
1. p107
- 예제 중 세번째
df["sepal with (cm)"].corr(df["sepal length (cm)"], method = "spearman")
df["sepal with (cm)"].corr(df["sepal length (cm)"], method = "kendall")

2. p128
각 단말 노드(leaf node)에 있는 데이터 분포가 해당 노드의 확률분포가 됩니다.
(다른 문단에서는 모두 잎사귀 노드라고 했으니 통일하는게 낫지 않을까 하는 생각)


- 목차(중분류까지)
Chapter 1. 데이터 과학 유니콘이 되자!
1.1 데이터 과학자는 단지 연봉이 높은 통계학자일 뿐이다?
1.2 왜 파이썬을 쓰나요?
1.3 한마디 더

[Part 1. 데이터 과학 필수 요소]
Chapter 2. 큰 그림으로 보는 데이터 과학
2.1 문제 파악
2.2 데이터 분석 및 이해 - 기초
2.3 데이터 분석 및 이해 - 전처리
2.4 데이터 분석 및 이해 - 데이터 탐험
2.5 특징값 추출
2.6 모델 수집 및 분석
2.7 결과 정리 및 발표
2.8 코드 배포
2.9 반복 작업

Chapter 3. 프로그래밍 언어
3.1 왜 프로그래밍 언어를 사용해야 하나요? 다른 대안은 없나요?
3.2 데이터 과학에서 사용하는 프로그래밍 언어
3.3 파이썬 속성 코스
3.4 문자열 데이터
3.5 함수 정의하기
3.6 파이썬의 공학용 라이브러리
3.7 개발 환경 및 라이브러리 소개
3.8 파이썬 관련 문서 및 참고 자료

Chapter 4. 데이터 먼징
4.1 생애 최악의 데이터셋
4.2 실수를 예방하는 방법
4.3 데이터 자체의 문제
4.4 데이터 형식 문제
4.5 데이터 형식 정리 예제
4.6 정규표현식
4.7 실제 현장 이야기

Chapter 5. 시각화와 대푯값
5.1 파이썬의 시각화 도구
5.2 아이리스 데이터셋
5.3 원형 차트
5.4 막대그래프
5.5 히스토그램
5.6 평균, 표준편차, 중간값, 백분위
5.7 상자그림
5.8 산포도
5.9 산포도와 로그 축
5.10 산포 행렬
5.11 히트맵
5.12 상관관계
5.13 안스콤 쿼텟 데이터셋과 대푯값의 한계
5.14 시계열 데이터

Chapter 6. 머신러닝 개론
6.1 역사적 맥락
6.2 지도학습과 비지도학습
6.3 학습 데이터, 시험 데이터, 과적합

 Chapter 7. 특징값 추출
7.1 일반 특징값
7.2 데이터 표본 여러개의 대푯값
7.3 복잡한 특징값
7.4 어떤 특징값을 예측할지 결정하기

Chapter 8. 머신러닝과 분류
8.1 분류기란?
8.2 현실적인 고려사항
8.3 이진 분류와 다범주 분류
8.4 예제 코드
8.5 다양한 분류기의 특징
8.6 분류기 평가하기
8.7 분류 기준값 정하기

Chapter 9. 의사소통과 문서화
9.1 일반적인 원칙
9.2 슬라이드 작성
9.3 보고서 작성
9.4 발표하기
9.5 코드 문서 작성하기

[Part 2. 데이터 과학 확장팩]

Chapter 10. 비지도학습: 군집화와 차원 축소

10.1 고차원의 저주

10.2 아이겐페이스와 차원 축소 예제

10.3 주성분 분석

10.4 스크리 도표와 차원 이해하기

10.5 요인 분석

10.6 주성분 분석의 한계

10.7 군집화


Chapter 11. 회귀

11.1 당뇨 진행 상황 예측 예제

11.2 최소제곱법

11.3 비선형 커브피팅

11.4 커브피팅 평가: R2과 상관관계

11.5 오차의 상관관계

11.6 선형 회귀

11.7 라소 회귀와 특징값 선정


Chapter 12. 데이터 인코딩과 파일 형식

12.1 일반적인 데이터 형식

12.2 CSV 파일

12.3 JSON 파일

12.4 XML 파일

12.5 HTML 파일

12.6 Tar 묶음 파일

12.7 Gzip 파일

12.8 Zip 파일

12.9 이미지 파일 형식

12.10 바이트 데이터

12.11 정수형

12.12 실수형

12.13 텍스트 데이터


Chapter 13. 빅데이터

13.1 빅데이터가 정확히 뭔가요?

13.2 하둡과 하둡 파일시스템

13.3 HDFS 사용하기

13.4 파이스파크 예제 코드

13.5 스파크 둘러보기

13.6 스파크 연산

13.7 파이스파크를 실행하는 두 가지 방법

13.8 스파크 설정하기

13.9 파이스파크: 더 깊이 살펴보기

13.10 스파크: 팁과 주의사항

13.11 맵리듀스 패러다임

13.12 성능 개선을 위한 고려사항


Chapter 14. 데이터베이스

14.1 관계형 데이터베이스와 MySQL

14.2 키-값 저장소

14.3 와이드 컬럼 저장소

14.4 문서 저장소


Chapter 15. 좋은 프로그래밍 습관 기르기

15.1 코딩 스타일

15.2 버전 관리와 깃

15.3 테스트 코드

15.4 테스트 주도 개발 방법론

15.5 애자일 방법론


Chapter 16. 자연어 처리

16.1 자연어 처리가 필요한 상황

16.2 언어와 통계

16.3 주식 관련 신문 기사의 감정 분석 예제

16.4 자연어 처리 소프트웨어 및 데이터셋

16.5 토큰화

16.6 BoW 특징값

16.7 단어 빈도와 문서 빈도 역수

16.8 n-그램

16.9 불용어

16.10 표제어 추출과 공통부분 추출

16.11 동의어 처리

16.12 품사 태깅

16.13 그 외 문제들

16.14 자연어 처리 심화과정


Chapter 17. 시계열 데이터 분석

17.1 위키피디아 조회수 예측 문제

17.2 시계열 데이터 분석 순서

17.3 시계열 데이터와 타임스탬프 데이터 비교

17.4 내삽법과 외삽법

17.5 신호 스무딩

17.6 간단한 데이터 전처리

17.7 추세와 주기성

17.8 윈도 적용

17.9 시계열 데이터의 특징값 추출

17.10 특징값 추출 심화 과정

17.11 푸리에 분석

17.12 시계열 데이터와 특징값


Chapter 18. 확률

18.1 동전 던지기와 베르누이 확률변수

18.2 다트 던지기와 균등확률변수

18.3 균등분포와 유사난수

18.4 비이산 불연속 확률변수

18.5 표기법, 기댓값, 표준편차

18.6 종속성, 주변확률, 조건부확률

18.7 확률분포의 꼬리

18.8 이항분포

18.9 푸아송 분포

18.10 정규분포

18.11 다차원 정규분포

18.12 지수분포

18.13 로그 정규분포

18.14 엔트로피


Chapter 19. 통계

19.1 데이터 과학과 통계학

19.2 베이지언과 빈도론자의 비교

19.3 가설검정

19.4 다중 가설검정

19.5 매개변수 추정

19.6 t 검정

19.7 신뢰구간

19.8 베이지안 통계학

19.10 베이지안 네트워크

19.11 선험적 확률 추정


Chapter 20. 프로그래밍 언어의 주요 개념

20.1 프로그래밍 방법론

20.2 컴파일과 인터프리팅

20.3 자료형 체계


Chapter 21. 알고리즘의 성능과 메모리 관리

21.1 예제 코드

21.2 알고리즘의 성능과 빅오표기법

21.3 정렬 알고리즘과 이진검색

21.4 평균복잡도와 분할상환분석

21.5 오버헤드 줄이기, 메모리 관리

21.6 팁: 수치연산 라이브러리를 이용하자

21.7 팁: 사용하지 않는 대용량 객체를 삭제한다

21.8 팁: 가능하면 내장 함수를 사용한다

21.9 팁: 불필요한 함수 호출을 자제한다

21.10 팁: 덩치가 큰 객체는 가급적 새로 만들지 않는다


[Part 3. 데이터 과학 특수 분야]

Chapter 22. 컴퓨터 메모리와 자료구조

22.1 가상 메모리

22.2 C 언어 예제

22.3 자료형과 배열

22.4 구조체

22.5 포인터, 스택, 힙

22.6 주요 자료구조


Chapter 23. 최대 우도 추정과 최적화

23.1 최대 우도 추정

23.2 커브피팅 예제

23.3 로지스틱 회귀 예제

23.4 최적화

23.5 경사 하강법과 볼록 최적화

23.6 볼록 최적화

23.7 확률 경사 하강법


Chapter 24. 고급 분류기

24.1 라이브러리 선정

24.2 딥러닝 기초

24.3 합성곱신경망

24.4 텐서

24.5 MNIST 숫자 필기 인식

24.6 순환신경망

24.7 베이지안 네트워크

24.8 학습 및 예측

24.9 마르코프 연쇄 몬테카를로 방법

24.10 파이엠시 예제


Chapter 25. 확률 과정

25.1 마르코프 연쇄

25.2 마르코프 연쇄의 종류

25.3 마르코프 연쇄 몬테카를로

25.4 은닉 마르코프 모델

25.5 비터비 알고리즘

25.6 랜덤워크

25.7 브라운 운동

25.8 ARMA 모델

25.9 연속 마르코프 과정

25.10 푸아송 과정


'Book Review > IT' 카테고리의 다른 글

처음 배우는 데이터 과학  (1) 2018.03.26
Akka 코딩 공작소  (0) 2018.03.07
  1. 바스코 2018.03.26 19:20 신고

    재밌어보이는 책이네요^^

+ Recent posts

티스토리 툴바