【5】 Jupyter Notebook Authentication 분석 : kt NexR 기술블로그 ‘21 테크리포트

생성일
2021/12/08 09:20
태그
2021년
상반기
테크리포트
기술블로그
kt NexR
글쓴이
jayden.jung
속성
ktNexR_techreport_Jupyter Notebook Authentication 분석.pdf
속성 1

I. 서론

Jupyter Notebook은 그 이전 프로젝트인 IPython과 연결해서 살펴보면, interative한 python 분석환경을 단일 process 로 제공하는 것으로 시작해서 사용자 입력과 분석 결과를 보여주는 front-end 와 back-end에서 명령어를 해석하는 kernel이라는 두 process를 분리하는 과정을 거쳐 front-end 를 web기반 application로 구축하는 단계까지 이르렀다. 특히, web application인 jupyter notebook은 인터넷으로 연결되어 있으면 어디서나 접근해서 분석 작업을 할 수 있고, 그 결과를 다른 연구자와 쉽게 공유할 수 있는 환경을 제공하는 편리함을 제공했지만, 역설적으로 더 외부 공격에 대한 위험에 노출이라는상황에 처하게 되었다. 그래서 이런 위험을 예방하기 위해서 jupyter notebook이 제공하는 기본적인 사용자 인증 방법과 과정을 확인해서 어떻게 보완 가능한지 검토해볼 필요가 있다.

II. 관련 기술/연구, 선행작업

Jupyter Notebook에서 사용 가능한 Authentication 방식 조사

1. 인증하지 않음

jupyter config 파일에서 c.NotebookApp.token, c.NotebookApp.password 모두 빈 문자열로 설정하면 인증 과정 생략하고 접근 가능하다.
인증 및 접근 제한 과정을 담당하는 다른 application layer 가 없다면 추천하지 않는다.
c.NotebookApp.token = '' c.NotebookApp.password = ''

2. Token 인증

사용자가 notebook server에 접근할 때 미리 정의(또는 서버가 생성)한 token을 이용한다.
인증 과정에서 최초 한 번만 사용한다.
Token 인증 설정 - config file에서 c.NotebookApp.token = '<generated>' 설정한다. - 기본 값이므로 생략하면 jupyter server는 token 인증 방식으로 동작한다. (단, password를 사용하지 않아야 한다.)
Token 생성하는 3가지 방법 a. 환경변수 JUPYTER_TOKEN : 환경변수로 전달한 값을 읽는다. b. 환경 변수 JUPYTER_TOKEN_FILE : 토큰을 저장한 파일 경로에서 읽는다. 공식 문서에 언급했으나 현재 버전에서 관련 코드 확인 불가능 c. random : config file에서 c.NotebookApp.password='' 으로 설정하면 (기본값이므로 설정 생략도 가능), 실행할 때 랜덤하게 생성된다.

3. Password 인증

config 파일에 c.NotebookApp.password 항목에 로그인 암호 설정한다.
token 과 password 인증은 서로 배타적이기 때문에 password를 사용하면 token 인증 방식은 동작하지 않는다.

III. 가설

jupyter notebook은 사용자 접근을 제어하기 위해 password 입력하거나 미리 발행한 token을 사용하는 2가지 방법을 제공한다. 물론, 인증을 사용하지 않도록 설정할 수 있지만, 보안적인 측면에서 권장하는 방식이 아니기 때문에 논의에서 제외한다. jupyter notebook이 web server 위에서 html 을 렌더링하는 web application이지만 인증 과정에서 id없이 passowrd만 입력하도록 구성한걸 보면, IPython 처럼 단일 사용자만 대상으로 한다는 설계 의도가 명확하게 드러난다. 거기에 http-api를 제공하면서 token을 이용한 접근 방식도 도입해서 단일 사용자를 위한 rest-api를 제공하는 web service의 성격도 지니고 있다. password 나 token 중 어떤 방식으로 인증하든 일반적으로 web service가 처리하는 방식을 따를 거라는 가정하에 비교적 최근에 도입한 token 기반 인증 과정을 상세하게 살펴본다.

IV. 해결 방법

Jupyter Notebook Config 속성 중 Authentication 관련 항목 조사

먼저 가장 소스를 분석하기 전에 인증에 영향을 주는 config 속성들을 살펴보자.
XSRF는 cookie 기반 인증 token을 사용할때 발생하는 사이트 요청 위조 취약점을 말한다. 이 취약점을 방지하는 옵션을 제공한다는 점에서 jupyter notebook이 인증 정보를 cookie로 관리하고 있다고 유추할 수 있다. 또, 사용자가 재정의할 수 있는 login_handler, logout_handler 옵션을 제공하는 점에서 내부적으로 인증체계가 잘 정비되어 있을 것으로 추측할 수 있다.

jupyter_server 분석

비교적 최근에 추가한 token 기반 인증을 분석해서 유추한 내용이 맞는지 확인해보자. jupyter notebook은 web ui interface와 web backend를 동일한 소스 코드 공간에서 관리했으나 jupyterlab이라는 차세대 notebook ui를 개발하는 과정에서 back-end 를 담당하는 부분을 jupyter_server이라는 project로 분리했다.
jupyter_server directory 구성
디렉토리 이름을 보면 jupyter_server 아래에 있는 /base, /auth 아래에 인증 관련 기능이 있을 가능성이 높다.
이 디렉토리들 아래에 있는 파일들을 중심으로 관계를 분석해본다.
<그림1 - /base, /auth 디렉토리 클래스 다이어그램1>
jupyter_server는 tornado web framework위에서 동작하기 때문에 상당수 class들이 tornado.web.Request_Handler 라는 최상위 class에서 파생하고 있다는 걸 확인할 수 있다. tornado에서 특정 http request를 처리하려면 필수적으로 이 handler classs를 상속해서 해당 url에 대응하는 사용자 handler를 구현해야한다.<참고 :Tornado's Subclassing RequestHandler > Login_Handler는 jupyter_server가 기본으로 제공하는 login class로서 공식 메뉴얼에서 설명했던 대로 인증 관련 처리를 담당한다. 로그인 방법을 바꿀 필요가 있는 경우 사용자 정의 class로 변경 가능하다. 여기에서는 jupyter server 인증 방법 중 token을 이용한 방법을 기준으로 그 과정을 살펴본다.
<그림 2 - jupyter server의 token 인증 sequence >
<그림2>에서 LoginHandler는 AuthenticatedHandler에서 파생했기 때문에 하나의 class로 볼 수 있지만 <그림1>처럼 사용자가 /login이 아닌 다른 경로로 접근하는 일반적인 상황을 반영해서 서로 다른 handler로 분리했다. jupytr server를 구동하면 console에 최초 접속용 token을 생성해서 사용자가 접근할 수 있는 url 형태로 보여준다.(header나 query string 형태로 접근가능)
사용자가 web client interface를 통해 jupyter_server에 어떤 요청을 하면, tornado server는 해당 요청의 url path, header, query string, body 등을 분석한다. 이 과정에서 tornado는 현재 요청한 사용자를 식별하기 위해서 해당 경로를 처리하는 handler의 current_user property에 접근한다. 최초 접근일 경우 이 property는 내부적으로 get_current_user()를 한번 호출한다. Tornado's Authentication and security 의 내용에 따르면 사용자 정의 인증은 get_current_user()을 재정의해야한다.
get_current_user()함수는 현재 사용자를 식별하기 위해 jupyter_server 구동할때 설정한 LoginHandler(여기에서는 jupyter_server가 기본 제공하는 class 사용)의 get_user() paython's classmethod함수를 호출하면서 자기 자신(호출한 handler object)를 인자로 넘긴다.
get_user()함수는
1.
요청한 handler에서 이전 user_id를 발견하면 반환이 handler의 path로 들어온 요청은 과거에 인증 통과했다면 user id는 handler의 _user_id 라는 cache 변수에서 확인 가능
2.
token 검증을 통과하면 새로운 uuid 형식의 user_id를 생성한 다음, 이 값을 login cookie와 호출했던 handler의 cache 변수에 저장하고 반환 - 2.1 token 검증 과정 : request의 url이나 Authorization header에서 식별한 'token'값과 jupyter_server 최초 구동시 생성한 token의 일치 여부 확인 - 2.2 login cookie 저장 : 호출 handler의 secure cookie에 user_id, handler의 base url 등을 저장 - 2.3 cookie name은 username-{request의 host} 양식이다.
3.
token 검증을 통과하지 못하면(이미 인증해서 token을 사용하지 않거나 , token 불일치) cookie에서 user_id 추출하고, 호출했던 handler의 cache 변수에 저장하고 반환
4.
모두 실패하면 'anonymous' 나 None 을 반환한다. get_current_user()는 최종적으로 get_user()에서 반환받은 user id를 반환한다.

V. 분석결과

jupyter server의 default login class가 제공하는 token 기반 인증 과정은 다음과 같은 특징을 가지고 있다.
AuthenticatedHandler에서 파생한 handler들은 기본적으로 request의 인증 여부와 처리를 server 설정에 명시한 login_handler_class에 위임한다.
Jupyter server의 default login handler인 LoginHandler는 단일 사용자 환경을 염두에 두고 설계했다. - 이 login handler는 자신을 호출한 handler마다 사용자 id를 cache용 변수를 할당해서 다음 접근시 바로 반환한다. 이 메커니즘은 여러 사용자가 접근할 때는 hit rate가 매우 떨어지기 때문에(request마다 다른 사용자가 접근한다면 매번 불일치) 다중 사용자 환경에서는 불필요한 과정이다.
Jupyter server는 Tornado web framework위에서 작성했고 인증 방식도 Tornado에서 권장하는 방식을 따른다. - Tornado는 간단하게 user의 반환 여부로 인증을 확인한다. - jupyter server의 인증 과정도 이 메커니즘에 맞춰 user id를 발급하고 식별하도록 구성했다.
최초 접근시 같이 전송한 token으로 올바르면 랜덤하게 생성한 uuid 형식의 사용자 식별 id를 발급한다.
사용자 id는 cookie에 저장해서 반환한다.
인증했던 사용자의 접근은 cookie에 있는 사용자 id 의 유무로 판단한다.
사용자 id를 별도 저장하는 저장소(DB나 파일)는 존재하지 않기 때문에 server를 재가동하면 다시 인증해야한다.
동일 client에서 접근하더라도 여러개의 사용자 id를 발급받을 수 있다. - 인증한 상태에서 token으로 새로운 접근을 시도하면 새로운 사용자 id를 발급해서 cookie로 전달하기 때문에 동일 client에서 접속하더라도 여러 개의 독립적인 접근을 허용한다.

VI. 결론

Jupyter Notebook이 채택한 cookie 기반 인증 정보 관리 방식은 최근 web 개발에서 선호하는 방식으로 XSRF 취약점 관련 옵션을 enable해서 사용한다면 web 보안 측면에서 적절하다고 평가할 수 있다. 만약, password나 token을 신뢰할 수 있는 환경과 구성원들이 함께 사용한다면 문제가 없겠지만, 신뢰할 수 있는 환경과 구성원이라는 전제가 사실상 불가능하기 때문에 여전히 보안적으로 불안정한 측면이 있다. login , logout handler를 별도로 정의해서 사용자 별로 관리하는 방법도 있지만, 인증 이후 모든 자원에 대한 제한없는 접근은 해결할 수 없다. Jupyter Notebook은 단일 사용자 기반 application으로 설계되어 있기 때문에 그 목적에 맞게 사용한다면 그 범위 안에서 충분한 보안을 제공한다. 범위를 넘어서 사용하지 않기를 권장한다.

VII. 후속연구/차후계획

JupyterHub은 여러 사용자가 Jupyter Notebook을 사용하기 위해서 필요한 기능들을 구현한 Project다. 다중 사용자 지원 과정에서 어떤 authentication 및 authorization 사용하는지 확인해보고자 한다.
【5】 Jupyter Notebook Authentication 분석 : kt NexR 기술블로그 ‘21 테크리포트
Reference
jupyter notebook 설정 및 명령 줄 옵션 : https://jupyter-notebook.readthedocs.io/en/stable/config.html
본 기술블로그에 게재되는 모든 컨텐츠의 저작권은 케이티넥스알(kt NexR)에서 가지고 있으며, 동의 없는 컨텐츠 수정 및 무단 복제는 금하고 있습니다. 컨텐츠(글/사진/영상 등)를 공유하실 경우 반드시 출처를 밝혀주시기 바랍니다. Copyright(c) 2021 kt NexR, Inc. All Rights Reserved.