Django 프레임웍을 서버로 사용하는 프로젝트에 모바일 클라이언트를 붙이게 되었습니다.

 
Do-Gyun Kim

Django 프레임웍을 서버로 사용하는 프로젝트에 모바일 클라이언트를 붙이게 되었습니다. 이때 문제가 발생했는데요, CORS관련된 것입니다. 모바일 클라이언트는 하이브리드 웹앱이라 모바일폰의 브라우저에서 접속하는 것과 비슷한 상황입니다. CORS는 아파치의 세팅으로 문제를 잡았는데, Django가 Cross origin문제를 한번 더 다루는 것이 문제가 되었습니다. CSRF라고 Cross Site Resource Forgery공격을 막기 위해 csrf_token이라는 것을 처음에 서버에서 발행하고 이것을 모든 통신에서 쿠키로 가지고 다니도록 하여 중간에 누군가가 악의적으로 끼어드는 것을 막고 있습니다. 이같은 구조 때문에 처음에 접속 페이지를 받아올 때 token을 가져오고 이후에 이를 통해 통신하는 것이 원천적으로 막히게 됩니다.
로그인을 예로 들자면, 클라이언트 쪽에서 로그인 폼을 만들고 서버로 로그인을 시도하려고 하면, 애초에 서버쪽에서 csrf_token을 받아오지 않았기 때문에 쿠키에 이 토큰이 세팅되어 있지 않아 서버가 로그인을 거부합니다. 따라서 이후 통신도 불가능하죠.
미리 서버에 접속해 csrf_token을 받아놨다가 접속할때 사용해 보려 했는데, 이번엔 웹킷 브라우저가 쿠키를 제 맘대로 세팅을 못하도록 막고 있네요. 결국, 로그인 시도에 실패 하고 있습니다.
해결 방법 혹은 우회 방법이 있을까요…? 서버측에서는 보안을 이유로 csrf 적용 해제를 거부하고 있습니다. OAuth등을 이용할 수도 있다는 얘기를 들은 것 같은데.. 좋은 방법이 있으면 소개 부탁 드리겠습니다 ㅠ.ㅠ/

  • Chinseok Lee

    서버 측에서는 풀어주셔야할 이슈같네요.

    http://www.django-rest-framework.org/topics/ajax-csrf-cors

    Donghyun Cho

    개인적인 생각으론 API를 통한 로그인에는 CSRF가 꼭 필요하다고 생각하지 않습니다. 로그인만 csrf를 풀어주는 건 어떠세요? https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#edge-cases

    Chinseok Lee

    웹페이지가 아닌, API 단에서는 CSRF 가 필요가 없다고 봅니다.

    Do-Gyun Kim

    의견 감사드립니다. 오히려 그렇게 생각하는 것이 맞군요…

    Donghyun Cho

    Chinseok Lee 님 API는 특별한 요구사항이 없다면 모든 타입의 클라이언트를 지원한다는 전제하에 만드는 것이고, 웹브라우저 또한 포함되어 있겠죠. 그럼 무조건 CSRF는 필요하다고 봅니다. 예를들면, 사이트를 하나 만드는데 ajax를 사용하여 API를 통해 데이터를 주고받는 경우가 되겠네요.

    박영록

    Donghyun Cho 어느 정도 일리 있는 논리라고 생각합니다만, API를 웹 이외의 클라이언트에서 호출하는 경우는 HTTP header 등 다양한 인증 수단을 사용할 수 있기 때문에 csrf가 없어도 무관한 것 같습니다. 실제로 페이스북, 트위터, 구글 등의 주요 Open API 제공자들은 POST 요청에서 csrf 토큰을 받지 않습니다. OAuth 등의 인증 수단을 쓰기 때문이죠.

    그런데 본문 내용으로 볼 때 이 문제는 csrf를 회피하고 말고의 문제라기보다, API가 따로 없고 그냥 웹 페이지만 있는 걸 클라이언트에서 요청을 하는 상황 같은데요. 그렇다면 그냥 폼이 있는 페이지를 요청한 다음 거기서 csrf token을 파싱해서 얻고, 그걸 POST 요청 날릴 때 보내주면 간단하게 해결 가능한 것 같은데요.

    한 가지 이상한 건 쿠키 사용을 못하는 상황이라는 건데, 웹킷이 쿠키를 딱히 막진 않는데, 어떤 상황에서 호출을 하는 건지 궁금하네요. 호출을 하는 클라이언트가 뭔지, 어떤 식으로 호출을 하는 건지 더 상세하게 적어주셔야 해결책을 제시할 수 있을 듯 하네요.

    Donghyun Cho

    쿠키가 생성이 안된다는 말이 의외인데요.. 처음엔 로그인페이지의 쿠키를 못쓴다는 말로 생각했습니다. 쿠키를 사용할 수 없다면 Django의 CSRF기능을 전혀 쓸 수 없어요.

    Do-Gyun Kim

    ㄴ 하이브리드 웹앱이라 웹킷 엔진을 사용하는데요, 말씀하신대로 쿠키에 박아서 보내면 되는데, 이때 Cors 위반이라면서 쿠키에 값이 박히질 않더군요. 제가 내공이 모자라는지 강제 세팅할 방법을 모르겠네요. Donghyun Cho

    Donghyun Cho

    박영록님의 글에 대한 댓글 입니다. Custom Header를 사용하는 인증방식이나 Oauth는 말 그대로 인증방식일 뿐이죠. 인증방식이 CSRF문제를 해결하진 못합니다. CSRF 토큰도 Ajax를 사용 시 X-CSRFToken을 헤더로 넣어서 보내야 하니깐요. Oauth도 구글에서 state attribute를 사용하여 CSRF문제를 해결하고 있는걸로 아는데요. 이 또한 CSRF 문제를 보안하기 위해 Oauth에 추가된 기능이 아닐까요? Oauth2가 각 회사들의 특성에 맞게 변형되어 쓰이고 있습니다만.. 질문자 님의 문제를 해결하기 위해 Oauth를 사용하는 것은 좀 과하다 생각했었어요. 🙂
    개인적인 생각으론 원천적인 문제 즉 쿠키생성이 안되는 이유를 먼저 파악하는 것이 우선인 듯 합니다. 이 문제를 해결하기 위해 Oauth로 갈아타는 건 좀 과하다고 생각되네요. 정 안되면 어쩔수 없는 선택을 해야하겠지만요.. ^^
    Session Authentication이나 Oauth나 둘 다 장단점이 있으니깐 잘 선택하세요.

    Donghyun Cho

    Do-Gyun Kim CORS문제라면 도메인이 다른 페이지를 불러오신다는 말인가요?

    Do-Gyun Kim

    ㄴ 좋은 조언 감사합니다. 쿠키 강제세팅만 해결된다면 사실 모든 문제가 해결입니다. 다시 시도해봐야겠네요!

    Donghyun Cho

    http://www.html5rocks.com/en/tutorials/cors/ 여기 함 보세요. CORS는 설정으로 해결할 수 있을꺼에요. 지금 어떤 식으로 앱을 만드는지 제가 전혀 감이 없어서 자세하게 답변을 드리기가 힘드네요 ^^

    Donghyun Cho

    심플한 거 하나 더 갑니다. http://quickleft.com/blog/cookies-with-my-cors

    Do-Gyun Kim

    Donghyun Cho 네. 일단 웹앱으로 뜨면 일단 웹서버는 localhost니까요.. 다른 서버에 접속하는 것 자체가 CORS입니다. 일반적인 HTTP 패킷은 서버에서 CORS를 풀어서 해결했는데, 일단 지금은 CORS위반이라고 쿠키가 세팅이 안되는 것으로 보입니다. CSRF토큰값을 일단 처음에 사이트에 접속해서 받아와 스트링으로 가지고 있거든요. 이걸 쿠키에 세팅해서 접속하려고 시도해 보니 쿠키에 박으려 할 때 CORS오류가 났던걸로 기억합니다.

    박영록

    Donghyun Cho OAuth를 권하는 이야기는 아니구요. 그보다 훨씬 가벼운 API Key 인증으로도 django의 csrf token 이상의 보안이 됩니다. csrf 공격은 사용자가 로그인된 상태에서 사용자가 원하지 않는 요청(주로 POST)이 날아가는 것인데, API에 인증을 걸어서 그 인증이 뚫리지 않는 이상 해당 사용자 계정으로 그 사용자가 원하지 않은 API call을 날리기는 매우 어렵다고 봐야죠.

    Chinseok Lee

    쿠키에 csrf 토큰 박는 건 어려워 보이는 데요. 폰갭을 쓰실 거 같은데, http 요청은 폰갭 플러그인으로 해결하셔야 되지 않을까요?

    혹은 django 서버 단에서 csrf token 을, 쿠키와 POST 데이터에서도 같이 찾아서 검증토록 해볼 수 있지 않을까요. ㅎㅎㅎ ;;;

    박영록

    Do-Gyun Kim 그러니까, HTML을 받아와서 웹뷰에서 로컬로 띄우는데 POST는 remote로 보내야 한다는 거군요. 웹앱도 구현 방식이 여러 가지가 있는데, 이 방식은 좀 곤란할 것 같네요.

    어차피 웹뷰를 쓸꺼면 그냥 리모트 서버에 접속하도록 하는 게 가장 쉬운 방법일 꺼구요. 굳이 HTML을 로컬에서 띄워야 한다면 서버와의 통신은 웹뷰에 맡기지 말고 그냥 url connection을 직접 열어서 해야 합니다. 그러면 CORS도 설정할 필요 없고, 쿠키도 그냥 됩니다. 응답으로 html이 오면 다시 웹뷰에 보여주는 등의 작업은 다 수작업으로 처리해줘야겠지만요.

    Do-Gyun Kim

    박영록 애플/구글에서 빈페이지를 바로 서버로 접속시키는 형태의 앱은 등록을 안해줘서 내용을 담고 있는 하이브리드 웹앱으로 구성했습니다.. 웹뷰를 통하지 않고 통신하려면 네이티브를 건드려야 해서 그것만은 좀 피해 가려고 했습니다 ㅠ.ㅠ 어차피 서버랑은 AJAX를 통한 xml이나 json통신만 하고 클라 화면 구성은 따로 하고 있었습니다..

    Do-Gyun Kim

    이진석 지금은 센차를 사용하고 있습니다. 말씀하신대로 아예 장고에서 csrf_token의 사용을 중지 시키고 개발단에서 직접 csrf토큰 처리를 하는 것도 확실한 해결책일 것 같네요..

    Do-Gyun Kim

    그런데 지금 새벽 4신데 다들 답변을 너무 열심히 달아 주시네요 ㅠ.ㅠ/ 이것이 개발자!

    Donghyun Cho

    다른 도메인의 쿠키를 읽어오는 방법은 있긴 한데, 그렇게 하더라도 API에 request할 때 다시 CORS 이슈가 발생하게 됩니다. 보아하니 RESTful이 정답인 듯 하네요. 박영록님 말씀처럼 해보는것도.. 네이티브 코드에서 웹뷰의 자바스크립트나 DOM에 엑세스가 가능한걸로 알고있는데.. csrf를 안써도 세션쿠키가 남아있지 않나요?
    ^^ 참고로 여긴 새벽이 아니네요..

    Donghyun Cho

    박영록님. ^^ RESTful 처럼 매 request마다 인증을 처리하는 방법에는 말씀하신 인증방법으로 처리가 되겠네요. Oauth 말고 간단한 Key인증이라 함은 어떤건지 링크나 좀 더 자세한 설명 부탁드려도 될까요?

    Do-Gyun Kim

    Donghyun Cho아, 외국에 계시군요~ 일단은 네이티브를 안건드리고 가보려고 용을 쓰는 중이거든요 ^^ 지금 딱 말씀하신대로 되서 stuck된 상태입니다 ㅠ.ㅠ 처음에 억지로 접속 시켜서 csrf_token을 받아 오는데 그게 제 쿠키에 세팅이 안되는 문제니까요;; 생각해 보니 세션이 있으니 굳이 csrf가 없어도 되겠군요…

    Donghyun Cho

    제 말은 쿠키로 생성되는 것들이 세션쿠키와 csrf쿠키가 있는데 csrf를 안쓴다 해도 Session 쿠키는 어떻게 처리하실런지 궁금해서요. django는 anonymouse user도 세션이 생성이 되는데.. 로그인부터 못하고 있는거죠?

    Donghyun Cho

    세션과 CSRF는 전혀 다른 기능을 위한것들이라.. ^^;;;

Advertisements