우아한형제들에서 진행하는 8월 세미나이다. 관련 정보는 여기에서 확인할 수 있다. 이전에 7월 세미나도 들었는데 U자형 개발자가 되기 위한 좋은 공부가 되는 것 같아서 이번에도 지원해서 들었다.
위에서 말한 것 처럼 내가 모르는 분야에 기초 지식을 쌓을 수 있을 수 있을 것 같아서 신청하게 되었고 이런 세미나를 통해 얻는 지식은 완전히 내 것이라고 할 순 없지만 나중에 누군가와 대화를 하다 얼핏 들은 기억이 나게 된다면 유효한 지식이 될 것이라 생각하며 열심히 생각하면서 들었다.
그리고 보안에 대한 지식이 부족하기도 했고 이번에 다룰 내용 중 JWT에 대해 보안 개발자가 어떻게 바라보고 있는지 궁금해서 신청하게 되었다.
이번 세미나 발표자인 권혁준 님(우아한형제들 인프라보안팀)이 이번 발표에는 본인 주관적 내용을 다룬 것임을 참고하라고 했고 나 역시 발표자가 전달하고자 하는 내용을 내 뇌의 필터를 거쳐 적는 것이기 때문에 여기에 적히는 내용이 세미나 내용과 100% 같지 않다. 이 후기에 적는 글은 세미나 내용에 내 경험과 의견, 지식을 더해 적을 예정이니 완전한 세미나 내용은 유튜브를 통해 확인하는 것을 추천한다.
먼저 1부와 2부로 나뉘고 마지막에 Q&A가 있었다. 1부에서는 발표자가 어떤 일을 하고 어떻게 지금까지 왔는지에 대해 간략하게 설명하고 세미나 중간에 질문을 하는 것에 대한 답을 하며 진행되었다. 2부에서는 본격 내용을 다루기 시작했고, 후반에는 세미나 도중에 들어오는 질문과 사전 질문지에 작성된 내용을 간추려 답변을 해 주는 식으로 진행되었다.
고객의 안전한 서비스 사용을 위한 보안 업무를 한다고 했다. 서비스의 취약점 분석 및 대응이나 클라우드 인프라 취약점 진단, 보안성 확보 등 여러 업무를 한다고 했다.
업무는 예방 성격을 띈다고 했다. 생각해 보면 예방 업무가 맞다.
두 개념을 혼동해서 사용하는 경우가 종종 있는 것 같은데 취약점 진단과 모의 해킹을 구분하자면 아래와 같다.
취약점 진단 :
즉, 해킹 가능성을 판단하는 정도인 수준이다.
모의 해킹 :
취약점 진단과 모의 해킹 중 하나만 활용하고 그러지는 않고 둘 다 사용한다고 한다.
결국 보안을 위해 시스템을 체크해 보는 것으로 개발자가 만든 서비스와 결투를 한다고 보면 된다고 말한다. 때문에 이런 과정에서 개발자와 대립이 잦고 이런 대립을 최소화 하기 위해서 시큐어 코딩을 해야 한다고 한다.
내가 아는 보안은 스프링 시큐리티를 통한 보안 정도인데 이게 프레임워크 종속적(?)인 도구에 의존하게 되면 나중에 이것 자체에 문제가 생겼을 때 문제가 커진다고도 했다. 예를 들면 최근에 문제가 되었던 log4j가 대표적인 예시라고 할 수 있겠다.
보안 가이드가 있다고 했다. 발표 자료를 캡쳐하진 않았지만 참고해 보자면 페이지가 300페이지가 넘어간다. 이것을 개발자에게 주면서 "이것들을 지켜서 개발해주세요."라고 하는 것은 싸우자고 하는 것이라 했다. 때문에 시큐어 코딩 내 모든 항목을 한 번에 적용하지 말고 중요도 순으로 차근차근 나눠 가이드를 해야 하고 개발자가 시큐어 코딩을 판단할 수 있도록 체크리스트를 만들어 제공하고 주기적인 시큐어 코딩 교육 또한 이루어져야 한다고 했다.
내가 생각해도 가이드 300페이지 주면서 이것에 맞춰 해달라 하면 답도 없을 것 같다. 팀 내에서 운용하는 코드 컨벤션도 맞춰야 하면서 보안에 대해서도 상당히 신경을 쏟게 되면 머리가 아플 것이다. 이것을 해결하는 방안도 적절하다고 생각한다. 중요도 순서로 꼭 필요한 부분을 어필하고 순차적으로 적용해 나가면서 중요도에 대한 교육.. 아직 내가 직접 경험한 것은 아니지만 일단 과정은 나쁘지 않다고 생각한다.
중간에 이런 질문에 대한 답을 해주기도 했는데 연차가 실력을 판가름 하지는 않는다고 했다. n년차 개발자가 있고 신입 개발자가 있을 때 n년차 개발자는 반복적인 작업만 하는데 신입은 모의 해킹 연습이나 대회에 나가면서 경험을 쌓는다. 이런 케이스를 판단할 때 신입 개발자가 더 잘 할수가 있다고 했다. 즉, 절대적 공부량에 대해 검토해 봐야 한다는 말이다.
이것은 근데 보안 개발자뿐만 아니라 모든 사람에게 통용되는 말이 아닌가 싶다. 스스로 발전을 멈추면 딱 거기까지인 사람이 된다. 항상 총 공부량에 집중해야 하고 어느 정도 공부량을 채우면 집중의 질에 대해 신경써야 한다고 생각한다. 아마 발표자 또한 같은 말을 하고 있었던 것 같다고 생각된다.
발표자는 중학생 때 노블레스라는 웹툰에서 엑스트라 인물 중에서 해킹을 해서 어딜 뚫어주고 이런 만화를 보다 빠져들었고 결국 특성화 고등학교에 진학했으나 개발을 모르는 상태에서 보안을 공부했기 때문에 잘 안되었다고 한다. 때문에 보안을 버리고 개발을 공부했지만 역시 이 길은 아닌 것 같다..싶다가 어쩌다 보안쪽으로 일을 하게 되어 지금은 괜찮은 것 같고 쭉 하고 있다고 한다.
보안 분야에도 어디를 공격하느냐에 따라 시작이 다르다 했다. 웹 해킹, 시스템 해킹, 모바일 앱 해킹 등 다양한 타겟이 있고 이런 타겟을 공격하는 공격 기법을 공부하기 전에 해야 할 것도 많다고 했다.
대표적으로는 최소한 웹이 이떻게 동작하는지 알아야 하고 어느 정도는 프로그래밍으로 구현도 할 수 있어야 한다고 했다. 그 후에는 OS나 네트워크에 대해 공부하면서 그 다음이 이제 공격 기법에 대해 공부해 나가면 된다고 했다.
발표자는 개발 -> 보안은 많이 못 봤다고 했다. 하지만 역으로 보안 -> 개발은 좀 봤다고 했다. 보안은 무엇을 공부해야 하는지 명확하게 정해져 있지 않고 본인의 루트를 만들어야 하는 분야이다 보니 이런 스타일의 공부나 일이 안 맞는 경우가 있다고 했다. 그러면서 개발에서 보안으로 넘어올 때 어려움이 있는데 입문 관련 자료가 많지 않기 때문이라고 한다.
간단하게 한글로만 체크해 뒀는데 아래와 같다.
출판사에서 먼저 연락이 왔고 이 주제를 선택한 이유는 입문서가 부족하다고 생각했다고 한다. 실제로 발표자가 고등학생때 보안 입문에 어려움을 겪었기도 했고 진입이 어려운 것을 직접 경험하고 나니 다른 사람은 조금 더 쉽게 입문할 수 있도록 돕고 싶었다고 한다.
발표자는 스스로 개발자가 아니기 때문에 개발자만큼 트렌드를 잘 알거나 전문가 수준으로 알지는 못 하기 때문에 내용이 어디까지나 주관적인 내용이라고 말했다.
서버의 부하를 줄이기 위해 클라이언트에서 처리하는 기능이 증가하고 있다. => 서버에서 처리해야만 하는 기능을 클라이언트에서 처리하면서 취약점이 발생한다.
효율적 개발을 할 수 있게 도와주는 프레임워크, 도구 등 사용 => 프레임워크에서 기능에 대한 설정을 부적절하게 하여 취약점 발생, 프레임워크 자체에서 발생하는 취약점으로 인한 영향도가 매우 커짐(예시 : log4j)
온프레미스 환경보다 인프라 구성이 쉽고 서비스 확장성이 좋은 클라우드 환경을 많이 쓴다. => 클라우드 환경 특성으로 인한 공격이 유입된다.
이처럼 발표자는 요즘 개발 트렌드에 맞춰 보안도 신경써야 하는 부분이 바뀐다고 했다. 실제로 이런것을 증명하는 내용도 있었는데 아래와 같다.
OWASP는 비영리 단체로 소프트웨어 보안 발전을 위해 노력한다. 여기서 가장 위협적인 웹 취약점을 연도 별로 체크해 주는데 이것이 OWASP TOP 10이다.
나는 이런 것은 처음 들어본다. 굳이 따로 알아보지는 않을 것 같지만 일단 알고 넘어가기 좋을 것 같아서 체크해 뒀다.
발표자는 개발 트렌드에 따라 개발의 종류가 달라진다는 것을 OWASP TOP 10의 변화를 체크해 보면서 알려주었다.
먼저, 인젝션이 1등이었는데 좋은 도구와 프레임워크가 많이 나오면서 개발자가 실수할 확률이 떨어졌다. 때문에 인젝션의 순위가 떨어졌다.
접근, 제어에 대한 부분도 있는데 이런 부분은 서버에서 해야 하는 기능을 클라이언트에서 처리하다 보니 순위가 높아지게 되었다고 한다.
SSRF취약점도 클라우드 환경을 많이 사용하다 보니 클라우드에서 사용 가능한 공격을 통해 공격하게 되면서 순위가 올라왔는데 이런 예시를 통해 각 취약점들은 개발 트렌드와 연결되어 있다고 볼 수 있다고 했다.
Insecure direct object reference의 약자로 아이도어, 안전하지 않은 직접 객체 참조, 부적절한 인가 등으로 표현한다.
이는 접근 제어와 관련이 있는데 취약점 1위인 Broken Access Control과 연관이 있는 취약점으로 관리자 권한을 자기 멋대로 이용할 수 있는 취약점이다.
수평적 권한 상승과 수직적 권한 상승이 있는데 각각 특징은 아래와 같다.
수평적 권한 상승
: 동일한 권한을 가진 다른 사용자의 객체에 접근할 수 있을 때 나랑 동일한 권한을 가졌지만 내가 다른 사람의 권한을 뻇어 이 사람처럼 행동할 때를 말 한다.
수직적 권한 상승
: 수직적 권한 상승은 본인이 지닌 권한을 넘어서는 기능을 수행한다.
조치 방안으로는 다음과 같다.
Server Side Request Forgery의 약어이다. 서버단에서 요청을 발생시켜 내부 시스템에 접근하는 취약점으로 외부 이미지를 불러오는 단계에서 발생하는 등 URI에 직접 요청해서 데이터를 받아오는 형태의 기능에서 주로 발생한다고 했다.
이때 질문이 하나 나왔는데 아래와 같다.
즉, SSRF 취약점은 서비스 자체를 공격하기 보다는 서비스를 통해 내부 시스템, MongoDB, Redis 등의 정보를 빼낼 수 있는 공격이라고 보면 된다.
조치 방안도 알려주었는데 아래와 같다.
JWT는 JSON Web Token으로 요즘 핫한 기술이다. 나는 프로젝트에 적용해 보지는 않았지만 공부할 때 잠깐 사용해 본 적은 있다. 다만 Stateless token 형식으로 사용을 했었고 발표자는 State ful하게 사용을 해야 한다고 했다. Stateful하게 JWT를 사용하기 위해서는 Refresh token을 활용해야 한다.
간단하게 Access token을 사용하면서 만료 기한을 짧게 설정하고 Refresh token을 통해 토큰 값을 갱신하면서 유지시켜주는 것으로 알고 있는데 토큰 자체를 탈취당하면 사실 답이 없어서 발표자는 추천하지 않는다고 했다. 조금 더 자세한 내용은 아래와 같다.
JWT는 통신을 수행하는 두 대상이 서로 보낸 데이터에 대해 신뢰할 수 있게 데이터가 인코딩된 토큰을 의미하는데 Stateless token이기 때문에 서버가 인증 작업을 수행하지 않기 때문에 인증 로직이 없어서 서버에 부하를 줄일 수 있지만 단점도 역시 서버에서 인증하지 않아 token에 대한 제어권을 잃어 관리할 수가 없다는 것에 있다고 했다.
그리고 발표 중에 말했지만 Stateful하게 관리해도 서버의 부하가 감당 못 할 정도는 아니기 때문에 사용에 대한 고민을 좀 하는 것을 권장하는 분위기였다.
다른 특징으로는 JWT는 사용자가 로그아웃을 하고 싶어도 Expired time이 되지 않으면 토큰이 만료되지 않아 실질적으로 로그아웃이 되지 않기 때문에 이때 세션 하이잭킹이 발생하게 되면 세션인 경우 만료시키면 되는데 토큰은 뺏겨버리면 대응이 안 된다. 왜냐하면 Stateless하기 때문에 서버에서 인증이 안 되기 때문이다.
요즘은 브라우저 내장 스토리지를 사용하는데 이런 이유로 XXS로 인한 토큰 탈취 가능성이 높아졌다고 한다.
하지만 위에서 언급한 Refresh token은 다르다. 이유에 대해선 체크하지 못 했지만 내 생각에는 이 토큰은 Stateful하기 때문에 애초에 만료 시간을 짧게하고 더 이상 토큰 인증을 해 주지 않으면 되기 때문인 것 같다.
조치 방안에 대해서도 역시 알려주었는데 아래와 같다.
조치 방안을 알려주면서 발표자는 JWT를 선호하지 않는다고 했고 토큰에 대한 검증 로직이 서버에 추가되면 기존 JWT에 비해 서버 부하는 증가하지만 Stateful 토큰만을 이용한 방식 보다는 여전히 부하가 적다고 했다.
발표 중 아래와 같은 질문이 들어왔고 답을 메모해 두었다.
Spring Bookt Framework의 서브 프로젝트로 스프링 부트를 이용해 운영되고 있는 서비스를 모니터링하고 관리하기 위한 기능을 포함한다.
HTTP 방식과 Java management eXtensions라는 Java API를 이용하는 방식이 있고 다양한 역할을 지닌 Endpoint들이 존재한다.
하지만 Actuator를 잘못 설정하게 되면 불필요한 Endpoint를 활성화 시켜 예상치 못한 Actuator 기능으로 인해 서비스의 기밀성, 무결성, 가용성을 침해당할 수 있다. 예시로는 환경 변수로 중요 정보를 저장한 경우나 중요 정보가 메모리에 올라가는 경우가 있는데 조치 방안으로는 7가지를 알려주었지만 7개 같은 6개로 압축해 적었다.
a. Shutdown Endpoint를 제외한 나머지는 Enable로 기본 설정이 되어 있는데 전부 Disable로 바꿔주고 필요한 것만 Enable로 변경해 사용해 줘야 한다.
b. 불필요한 Endpoint를 Expose할 경우 잠재적 위험이 될 수 있다.
a. 서비스 가용성을 침해할 우려가 있다.
b. 기본적으로 Disable 되어 있으니 바꾸지 말자.
a. Actuator가 다양한 기능을 가진 만큼 공격자는 Actuator Endpoin를 Scanning 한다.
b. 서비스 운영 포트와 Actuator 포트를 분리할 경우 외부에서 접근을 차단하고 외부에 노출을 할 필요가 없기 때문에 방화벽 설정 등을 사용해 내부에서만 접근 가능하게 한다.
a. 운영자, 개발자가 주로 접근하는데 인가된 사용자만 접근 가능하게 IP를 제어한다.
a. Actuator 경우 /acturator/[Endpoint]
가 기본 경로인데 공격자가 이 기본 경로를 토대로 Scanning을 함으로 경로만 변경해 주어도 안전해 질 수 있다.
b. 경로 변경시 유추하기 어려운 문자열의 경로로 설정할 것을 권고한다.
a. 권한 있는 인증이 된 사용자만 다루는 게 보안상 좋다.
발표 중 발표자가 보여준 예시 사진이다. application.properties에 설정을 해 주면 된다.
세션이 문제가 된다. 세션은 와스 종속적이라 잘 안 쓰지만 Redis를 운영해 토큰을 각 와스가 가져갈 수 있게 운영하는 쪽으로 이용하는 것 같다.
설계상 보안을 하지 않는 경우라는 항목 자체가 취약점에 속한다. 때문에 설계할 때 참여한다.
대응을 했다. 안 할 수가 없었다. 프레임워크를 사용하면 이에 의존적인 문제로 취약점이 나타날 수 있다고 했는데 log4j가 딱 그 경우이다.
한다. 외부 스캐닝을 막아내는 비용이 오히려 더 크다. 때문에 모의 해킹을 한다.
스프링 시큐리티, 리엑트 xss, 스프링 부트에 thymeleaf에 있는 텍스트, 유텍스트 등을 활용하고 패치가 나오면 패치를 하되 가능하면 보안팀과 협업을 하는 것을 권장한다.
"저희 배포해야 하는데 언제되요?"라는 말을 많이 듣는다. 안전하고 빠른 서비스를 제공해야 하는데 이 부분은 현실적인 부분인데 생각하기엔 의사결정권자까지 보안의 중요성을 알 수 있게 취약점이 발생했을 때 이 취약점으로 인해 어떤 결과를 초래하는지에 대해 알려주고 소통을 해야 한다. 그리고 시큐어 코딩 가이드나 체크리스트 등을 간단하게 보안팀에서 만들어 제공 받는 것도 방법이다.
우아한 입사 전에는 보수적이고 딱딱해서 강압적인 보안 업무를 진행했다. 우아한에 와서는 강압적이지 않고 의견을 접고 들어간다. 이 사항을 고쳤을 때 생기는 문제에 대해 같이 토의하는 등..을 진행한다. 때문에 보안을 공부하더라도 개발을 알아야 한다.
개인적인 생각으로 보안팀이 잘못했다. 재현을 하고 싶으면 보안팀에서 해 주는 게 맞다. 개발자가 재현할 수 있게 보안팀에서 알려줘야 한다.
클라이언트에서 서비스의 보안에 관련된 무언가를 하면 안 된다고 생각한다. 클라이언트 소스 코드는 피씨에 다운되기 때문에 이것을 분석해서 우회 공격을 충분히 할 수 있다. 때문에 클라이언트 의존적인 보안은 하면 안 된다. 리엑트, 뷰 등을 쓸 텐데 소스맵을 운영상에 노출 안 하는 것을 권고한다. 분석은 다 되고 누가 더 코스트를 높게 잡는가 따라 다르기 때문에 공격해 봐야 의미가 없겠다는 생각을 심어주도록 해야 한다.
JWT는 서버의 터치를 받지 않아 마음대로 갱신시킬 수가 없다. 로그인 상태를 유지하는 서비스를 하기 위해 JWT는 필요하다. 때문에 장점이 사라진다는 느낌이 들지는 않는다.
인증은 스테이트 풀해야 한다. 하지만 JWT는 그렇지 않다. 리프레쉬 토큰이 JWT로 발급한 엑세스 토큰을 갱신하는 용도인데 만료되야 일어난다. 즉, 빈도가 적다.
그 트래픽으로 인해 디비에 쿼리가 많아져서 서버 부하가 늘어난다 등 큰 단점이 일어나진 않을 것 같다. 보안 입정에선 JWT 만료 시간을 짧게 해야 하고 이로 인해 트래픽이 발생하겠지만 서버에 부하를 줄 정도는 아니다.
이래서 JWT를 딱히 권고하진 않는다. 리프레쉬 토큰 탈취도 걱정해야 한다.
UUID 형태로 HTTPOnly 옵션을 걸어 사용하는 것을 추천드린다. 서버 비용이나 부하는 있을 수 있는데(서버에서 인증을 거치기 때문에) 스테이트풀 토큰을 사용할 것을 권장한다.
메모리 안에 있는 것을 기준으로 뽑아내기가 까다롭다. 물리적으로 뺏던가 기기가 완전 장악당해야 하는 기준이다.
코드 안에 남기는 것은 매우 비추천이다. 프로가드 정도의 난독화는 충분히 뽑아서 풀어낼 수 있다. 이건 환경에 따라 보안팀과 협업을 통해 해결해야 한다.
레고를 만들어 봐라 레고를 만드는 게 좋다면 개발자, 만든 레고를 부수는 게 좋다면 해킹이 맞을 수도 있다..ㅋㅋ
부족한 지식을 채우기 위해 들은 세미나에서 바탕 지식을 많이 얻어갈 수 있었다. 가능하면 잘 모르는 분야의 세미나도 참여하려고 하는데 아직 내가 좁은 길만 가고 있기 때문에 지나가면서 최대한 시선을 넓히기 위함이다.
JWT의 장점만 보고, 이 기술이 핫하기 때문에 그저 사용하는 게 가능하면 좋다라고 생각했는데 세미나를 듣고 생각이 달라졌다. 가능하면 스테이트 풀 하게 관리하는 방법과 엑츄에이터에 대해 조금 더 알아봐야 겠다는 생각과 추후 보안 관련자와 협업할 때 조금 더 말이 통할 수 있게 된 것 같은 느낌이다. 물론 여기서 얻은 지식을 갈고 닦는 것은 내 일이지만 세미나를 듣는 시간과 정리하며 공부하는 시간이 전혀 아깝지 않았다.