Web 관련/Tornado

Tornado (Python web server) #4_ Authentication and security: Cookies and secure cookies

Tigercow.Door 2017. 10. 22. 14:08


안녕하세요.

오늘은 Tornado web framework를 이용한 Authentication and security를 알아보도록 하겠습니다.

공식문서를 확인하시면  'Authentication and security' 을 주제로한 몇가지 예제가 나와있습니다.

오늘은 그 중 첫번째인 Cookies and secure cookies 에 대해 공부해보겠습니다.


직접적으로 Tornado를 이용하기에 앞서서 먼저 cookie라는 것에 대해 알아볼게요.


1. 쿠키(cookie)란?

쿠키란 특정 웹서버에 대한 접근 정보를 담고 있는 것 입니다.

많은 분들께서 웹브라우저를 이용하시면서 특정 웹사이트가 로그인 정보를 기억한 경험이 있을거에요.

한번 로그인한 웹사이트를 다음에 접속할때는 따로 ID와 password를 입력하지 않아도 자동으로 로그인 되는 상황이죠.


이렇게 로그인 정보를 기억할때 웹 사이트에서 여러분의 로그인 정보를 쿠키(Cookie)로 저장하게 됩니다. 그리고 다음번에 여러분이 해당 사이트에 접근하게되면 해당 쿠키를 통해서 자동으로 로그인이 되도록 하는 것이죠.

순서를 통해 한번 더 이해해보겠습니다.


웹 브라우저  ---------->    웹서버

  1. 요 청


웹 브라우저  <---쿠키----    웹서버

2. 응 답: 쿠키생성 및 저장

3. 웹 브라우저는 쿠키저장소에 쿠키 저장


웹 브라우저  ---쿠키---->    웹서버

4. 쿠키를 통한 요청


웹 브라우저  <----------    웹서버

5. 응답: 받은 쿠키를 이용한 응답



위와 같은 순서로 쿠키가 생성되고 이용된다고 보시면 됩니다.


이러한 쿠키는 클라이언트에 저장된다고 하는데, 쉽게 말해서 사용자의 컴퓨터에 저장된다고 생각하시면 됩니다.

그럼 쿠키에 개인정보나 중요한 정보가 저장되어 있다면 보안상으로 많은 문제를 불러올 수도 있겠죠?

따라서 쿠키에 중요한 정보를 담지 않고 서버에 중요한 정보를 저장하여 이용하는 방지대책도 있으며

쿠키에 저장되는 정보자체를 암호화 하는 방법도 있습니다.


오늘 포스팅에서는 쿠키가 생성되고 저장되는 것을 확인하고,

방지대책으로써 쿠키에 저장되는 정보자체를 암호화시켜보는 과정을 진행해보겠습니다.


2. 쿠키생성

우리는 tornado에서 set_cookie 메소드를 이용하여 쿠키를 생성할 수 있습니다.

이렇게 만들어진 쿠키는 안전하지 않으며 사용자에 의해 쉽게 변경될 수 있습니다.

(보안성 강화는 뒤에서 알아보겠습니다.)


그럼 코드를 직접 작성하여 쿠키가 생성되는 것을 확인해보겠습니다.


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
import tornado.httpserver
import tornado.ioloop
import tornado.web
 
class MainHandler(tornado.web.RequestHandler):     
     def get(self):
          if not self.get_secure_cookie("mycookie"):
               self.set_secure_cookie("mycookie","myvalue")         
               self.write("Your cookie was NOT set yet!")
          else:
               self.write("Your cookie was set!")
               items = ["Item 1""Item 2""Item 3"]                  
               self.render("template_test.html", title="My title", items=items, sayHello=self.sayHello) 
               
     def sayHello(self, name):
          return 'Hello, '+name + '!!!'
 
application = tornado.web.Application([     
     (r"/", MainHandler),   
]) 
 
if __name__ == "__main__":     
     http_server = tornado.httpserver.HTTPServer(application)     
     http_server.listen(8888)     
     tornado.ioloop.IOLoop.instance().start()
cs


지난 번 포스팅에서 진행된 코드에서 수정을 진행하였습니다.

7번 라인을 보시면 현재 사용자가 쿠키를 가지고 있는지 확인합니다.

사용자에게 쿠키가 없다면 8번 라인을 통해 mycookie라는 키(key)와 myvalue라는 정보(value)를 가진 쿠키를 생성하고

9번라인을 통해 화면에는 Your cookie was NOT set yet! 이라는 문구를 띄어줍니다.



그럼 이 화면을 보고 있는 상태라면 이미 8번 라인이 실행된 것이므로 쿠키가 생성되었겠죠?

다시 접속해보면 아래와 같이 화면이 바뀌게 됩니다.


네, 쿠키가 생성되어서 이제 코드 8,9 라인이 진행되지 않고 10번라인부터 진행이 되었습니다.

이제 생성된 쿠키를 확인해볼게요.

웹 콘솔창(Shift + I 을 누른뒤 Console 클릭) 또는 명령어 자체를 주소 창에 입력하시는 것을 통해 확인 할 수 있습니다.

javascript:document.cookie 를 입력합니다.



그럼 좀 전 코드에서 확인한 바와 같이 mycookie 라는 키(key)와 그에 대응하는 myvalue 라는 정보(value)가 생성되어 저장된 것을 확인할 수 있습니다.

하지만 처음에 알아본 것과 같이 이렇게 쿠키가 저장되어 있다면 사용자가 이를 쉽게 수정할 수 있으며 또는 쉽게 정보를 해킹당할 수 있습니다.

예를 들어 특정 웹사이트에서 권한을 1~5로 나누고 A라는 유저는 2 정도의 권한을 가지고 있었는데, 위와 같이 쿠키의 정보가 보안이 되어 있지 않다면 사용자가 2라는 권한을 5로 수정하여 허락되지 않은 행동들을 취할 수 있을 것 입니다.



3. 쿠키 암호화 하기

따라서 우리는 쿠키에 중요한 정보를 저장하지 않거나, 쿠키의 정보 자체를 암호화하는 방법을 이야기했습니다.

그 중 tornado에서는 쿠키의 정보 자체를 암호화 하는 함수를 제공하고 있습니다.

set_secure_cookieget_secure_cookie라는 함수를 제공하고 있으며 이러한 함수들을 사용하기 위해서는 cookie_secret이라는 값을 설정해야 합니다. 

set_secure_cookie를 통해 생선된 인증된 쿠키는 암호화된 정보에 추가적으로 timestamp와 HMAC인증이 저장됩니다. 만약 쿠키가 오래된 것이거나 인증이 맞지 않다면 get_secure_cookieNone값을 리턴하여 쿠키가 존재하지 않는 것처럼 처리하게 됩니다. 

위의 두가지 함수를 이용한 python 코드는 아래와 같습니다.


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
import tornado.httpserver
import tornado.ioloop
import tornado.web
 
class MainHandler(tornado.web.RequestHandler):     
     def get(self):
          if not self.get_secure_cookie("mycookie_2"):
               self.set_secure_cookie("mycookie_2","myvalue")         
               self.write("Your cookie was NOT set yet!")
          else:
               self.write("Your cookie was set!")
               items = ["Item 1""Item 2""Item 3"]                  
               self.render("template_test.html", title="My title", items=items, sayHello=self.sayHello) 
               
     def sayHello(self, name):
          return 'Hello, '+name + '!!!'
 
application = tornado.web.Application([     
     (r"/", MainHandler),   
],cookie_secret="owb4t22n3or$239fn=nefo23/1rf13"
 
if __name__ == "__main__":     
     http_server = tornado.httpserver.HTTPServer(application)     
     http_server.listen(8888)     
     tornado.ioloop.IOLoop.instance().start()
cs


7번 코드를 확인하면 이전과 달리 mycookie_2 가 존재하는지 확인합니다.

그리고 존재하지 않는다면 8번 라인에서 set_secure_cookie 함수를 통해 mycookie_2라는 키와 myvalue 라는 값을 가진 쿠키를 생성합니다. 이후의 동작은 이전의 코드와 동일합니다.

추가적으로 20번라인에 cookie_secret 이 새로 추가된 것을 확인하실 수 있습니다.

저는 해당 cookie_secret을 무작위로 입력하였습니다.

해당 코드로 웹에 접속해 본다면 이전과 같은 결과를 얻을 수 있습니다.

첫 접속에서는, Your cookie was NOT set yet! 이라는 화면이 뜨고 다시 접속하면 필요한 정보들이 출력됩니다.

그럼 다른점을 확인해볼까요?

아까와 같이 웹 콘솔창을 띄우거나 주소창을 통해 이전과 같은 명령어(javascript:document.cookie)를 입력합니다.


그럼 이전에 생성된 mycookie라는 키와 방금 생성된 mycookie_2 라는 키, 두개에 대한 정보를 함꼐 확인하실 수 있습니다.

그 차이점이 명확히 보이시나요?

mycookie_2 라는 키에 대응되는 정보(value)는 암호화되어 사용자가 무슨내용인지 알 수 없습니다.

이런 암호화된 정보를 확인하기 위해서는 위에서 추가한 cookie_secret이 필요할 것 입니다.


토네이도의 공식문서를 통해 확인해보면, 이러한 쿠키는 무결성(integrity)를 보장하지만 기밀성(confidentiality)는 보장하지 않는다고 합니다. 즉, 우리가 쿠키에 대한 정보를 확인할 수 있었듯이 사용자가 쿠키를 볼수는 있지만 수정할 수는 없습니다.

그리고 cookie_secret는 비밀로 유지되어야 하며 이 키의 값을 얻은 사용자는 자신의 쿠키를 생성하거나 수정할 수 있습니다.

기본적으로 tornado의 보안 쿠키는 30일 후에 만료됩니다. 이를 변경하기 위해서는 set_secure_cookie함수에서 expires_days 키워드와 get_secure_cookie의 함수에서 max_age_days 키워드를 수정하면 됩니다.

보다 자세한 정보가 궁금하다면 tornado의 공식문서를 참고하시기를 바랍니다.


이렇게 하여 쿠키(cookie)에 대해 알아보고, Tornado에서 쿠키를 생성하고 보안성을 높이는 방법을 알아보았습니다.

다음에는 유저 인증(User authentication)에 대해서 알아보도록 하겠습니다.

수정되어야 할 점에 대한 피드백이나 문의사항은 덧글 및 이메일(doorbw@outlook.com)을 이용해주세요!

728x90