서론
‘보안’은 주니어 개발자가 제대로된 역량을 쌓기 가장 어려운 부분입니다. 국내 주니어 개발자 평균적인 보안 인식은 매우 형편없는 수준입니다. 그냥 JWT가 좋다니까 JWT쓰고, SMS 인증을 다들 넣으니까 넣습니다. 그 기술이 어떻게 보안에 기여하는지 텍스트로는 알지만 어떤상황에서 어떤형태로 의미가 있을지 깊게 고민하고 피부로 느끼지는 못하는 경우가 많습니다. 하지만 이런 상황을 주니어 개발자 입장에서 거꾸로 해석하면 오히려 좋은 기회라고 생각합니다. 만약 주니어 개발자가 보안에 대해 남들보다 더 고민하고, 그 결과물을 코드에 녹여낼 수 있다면, 고만고만한 개발자들 사이에서 Brilliant하고, 남다른 개발자가 됩니다.
본론
소프트웨어 보안의 특성
왜 대부분 개발자는 보안에 대해 깊게 고민하지 않을까요?
보안에는 이런 특성이 있습니다.
1. 큰 보안 사고가 발생할 때까지 아무런 문제가 되지 않습니다.
- 만약 쇼핑몰의 상품 조회 기능을 잘못 구현한다면 어떻게 될까요? 당장 내일부터 유저 불만이 쏟아질 겁니다.
- 유저 불만은 개발팀의 제 1 우선순위 해결과제로 올라옵니다. 그렇기에 대부분 빠른 시간안에 해결됩니다.
- 하지만 보안을 잘못 구현하면 어떻게 될까요? 유저들은 해킹에 노출되어 있는 상황에 대해서는 불만이 없습니다. 실제로 해킹으로 피해를 보는 상황이 생겨야만 불만이 생깁니다.
- 즉, 기능을 잘못 구현하면 기능배포시점부터 바로 욕을 먹지만, 보안을 잘못 구현하면 사고가 날 때까지 욕먹을 일이 없습니다.
- ‘해킹을 당하지 않았다’는 ‘보안이 튼튼하다.‘와 다른 말입니다. 사고가 발생하지 않는건 대부분 서비스가 굳이 해킹을 할 만한 가치가 없기 때문이지, 보안이 튼튼해서 발생하지 않는 것은 아닙니다.
- 실제로 사고가 발생하는 서비스는 밸류가 엄청 크고 성공한 서비스들입니다. 이런 서비스는 자본도 많기에 보통 유능한 시니어 개발자들이 관리하고 있는 경우가 많습니다. 그러니까 대부분의 주니어 개발자는 유의미한 보안 사고를 경험할 일도 없고, 바쁘게 기능 구현만 하다보면 보안 고민을 해야한다는 사실조차 잊어버리곤 합니다.
2. 보안은 개발자를 귀찮게 합니다.
- 보안을 숫자로 표현해볼때 99점의 보안을 가지고 있는 서비스와 10점짜리 보안을 가지고 있는 서비스가 유저에게 지원하는 기능은 같습니다.
- 10점짜리 보안을 99점으로 만들기 위해 고민하는 건 어렵고 매우 지루한 일입니다.
- 하지만 어차피 10점짜리 보안이라도 (1.)에서 언급한 이유 때문에 사고는 발생하지 않으니, 대부분은 이런 노력을 알아주지 않습니다.
- 이 때문에 가장 중요한 일임에도 항상 기능개발보다 우선순위가 떨어지고, 나중에 시간나면 개선해야 할 일로 미루게 됩니다. (경험상 대부분의 경우 그 ‘나중에 시간이 난다면’ 이라는 상황은 절대로 자연스럽게 오지 않습니다.)
3. 보안은 유저도 귀찮게 합니다.
- 보안은 강해질수록 유저는 불편해지고, 보안이 허술할수록 유저는 편해집니다.
- 세상에 100점짜리 보안은 없습니다. 아무리 튼튼한 보안이라도 틈이 있기 마련입니다. 그래도 개발자는 99점을 지향하려고 노력합니다.
- 하지만 99점에 가까워질수록 유저는 점점 귀찮아집니다. 자동 로그인도 평생 해주면 편할텐데, 다른 기기로 접속하려면 보안 때문에 다시 로그인도 해야하고, ‘111’같은 단순한 비밀번호도 사용하지 못하게하고 때로는 특수문자까지 사용하라고 합니다. 유저는 기억하기도 힘들고 귀찮아집니다.
- 그래서 서비스는 *‘최소한의 보안 수준’*을 만족하는 선에서 유저에게 불편함을 주지 않으려고 타협안을 제시합니다. 서비스 중요도에 따라 각각 70점, 80점짜리 보안을 가진채 서비스됩니다. 그래서 JWT같은 조금은 허술하면서도 편리한 타협안들이 많이 사용되는 것입니다.
- 하지만 *‘최소한의 보안 수준’*을 만족하지 못하는 10점짜리 보안은 차라리 없는게 낫습니다. 그냥 로그인 검증 없애고 로그인 안해도 기능 전부 쓸 수 있게하는게 서비스 관점에서 더 유익하다는 의미입니다. 어차피 마음만 먹으면 뚫을 수 있는 상황은 똑같은데 적어도 유저는 편해지니까요.
- 예시)
- 헬스장 개인 사물함에 자물쇠를 걸어놨다고 해봅시다. 저는 사물함에서 물건 꺼낼때마다 열쇠를 꼽아서 열어야합니다. 아주 귀찮습니다.
- 그런데 자물쇠가 걸려있는 사물함이 스티로폼 재질로 되어있습니다. 제가 사물함 안에 치약칫솔 따위를 넣어놓는다면 아무도 관심 없겠지만, 현금다발을 넣어놓는다면 누군가 그냥 주먹으로 스티로폼 부셔서 가져갈겁니다.
- 그러면 사용자는 무엇 때문에 자물쇠를 걸어놓고 귀찮게 매번 열쇠를 꼽아야할까요? 그냥 자물쇠를 안걸고 편하게 쓰는게 낫지 않을까요?
4. 그래서 보안 솔루션은 항상 서비스 중요도와 특성에 맞는 타협안으로 귀결됩니다.
- 이 최적화 솔루션을 찾는 과정은 귀찮기 때문에 보통은 깊게 고민하지 않고 그냥 다들 많이 쓰는 장치들을 씁니다.
- 각 보안 도구들은 취약점이 있으며, 이를 보완하기 위해 중첩으로 걸어놓기도합니다. Firebase Auth를 쓰고, 유저에게 비밀번호를 요구하고, 그걸 암호화하고, DB Access Key를 따로 관리하고, 이런 것들이 각 취약점을 보완하는 다중 장치입니다.
- 하지만 위에서 언급했듯이 보안을 강화할수록 유저와 개발자 모두가 불편한 경험을 겪기 때문에 서비스에 적합한 수준의 보안이 무엇인지 고민하고, 이를 충족시키기 위한 솔루션을 도입하는 것은 아주 중요한 일입니다.
(추가) 실제 취약점 시나리오 예시
이해를 돕기위해 가상의 서비스와 엮어서 예를 들어보겠습니다.
당연히 MVP 단계에서는 빠른 구현이 중요하기 때문에 아무리 유능한 개발자라도 중요한 부분인 걸 알면서도 일부분 생략하면서 구현하곤 합니다.
이런 예시가 문제라고 말하고 싶은 것은 아니고, 단지 현재 서비스가 어떻게 구현되어있는지 정확히 이해하고 인식수준을 동기화 하는 것은 중요하기에 사례로 가져와봅니다.
아래 설명하는 예시는 해킹이라고 말할 수 있는 수준도 아니고 컴퓨터 공학과 대학생 1학년이라도 악의를 가지고 조금만 시간을 쓰면 충분히 할 수 있는 일입니다.
e.g.)
-
제품을 둘러보던 개발자가 심심해서(or 악의를 품고) 크롬 개발자 도구를 켜고 어떤 요청이 있는지 둘러봄.
- “오호. 리뷰 조회 할 때 아래 API로 조회하네?”
GET : https://api.example.com/store/1/reviews
- “오호. 리뷰 조회 할 때 아래 API로 조회하네?”
-
“그냥 내가 따로 GET요청 보내서 데이터 저장형식 확인해볼까. 재미있다.”
- 이미지 주소들은 AWS에서 관리하고, 버켓은 저런식으로 관리하고 있구나.
https://s3.ap-northeast-2.amazonaws.com/example-storage/reviews/47831f08-9c5b-418b-8f01-8492a0ba7f59
- 이미지 주소들은 AWS에서 관리하고, 버켓은 저런식으로 관리하고 있구나.
-
GET 요청 있으니까 DELETE도 있겠지? 심심한데 똑같은 주소로 DELETE 보내볼까?
- “어? 내가 쓴 리뷰도 아닌데 왜 삭제 되어버려?”
- “아까 본 리뷰 어디갔어? 클릭 한번 딸깍 했는데 진짜로 삭제 돼버렸네” (총 리뷰 80 → 79)
- “그러면 내가 마음만 먹으면 스토어 리뷰 다 삭제해버릴 수 있잖아? 심심한데 상품도 삭제해버리고 주문기록들도 삭제해버릴까?”
Summary
이런 예시는 너무 극단적이지만, 또 일어나지 않는다고 장담할 수도 없는 일입니다. 기획, 디자인 등 비 개발자 입장에서는 단순히 기능이 동작하는 것 이외에 이런 디테일한 부분은 캐치할 수 없기 때문에 개발팀에서 항상 예민하게 신경을 곤두세우고, 신경써야합니다.
민감한 데이터를 다루는 서비스일수록 이런 사소한 것들도 두번 세번 신경써야 추후에 일어날 수 있는 큰 사고들을 예방할 수 있습니다.
보안을 식당에 비유하자면 위생과 같습니다. 주방장이 손도 안씻고 요리한다고해도 음식을 만들 수 있고 팔 수 있습니다.
하지만 식당이 커지고 손님이 많아지면 누군가는 식중독에 걸리고 문제가 될 것입니다. 그때가서 부랴부랴 더러운 주방을 청소하고, 이미 손씻고 청소하는게 습관화되지않은 직원들의 인식을 바꾸는 건 매우 어려운 일일 것입니다.
댓글 (0)
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요.