어떻게 하면 더 나은 소프트웨어를 만들 수 있을까? – 인터뷰 시리즈 part 2, Brian Warner와 함께

이 글은 이 쓴 How can we write better software? – Interview series, part 2 with Brian Warner의 한국어 번역본입니다.

이 글은 이곳 모질라 Hack에서 새로 시작한 인터뷰 시리즈의 두번째 기사입니다.

“개발자로서 어떻게 하면 더 멋진 소프트웨어를 만들 수 있을까요?”

간단하지만 결코 간단히 답할 수 없는 질문입니다. 멋진 코드를 작성하는 것은 힘든 일입니다. 수년간의 경력을 쌓은 개발자들에게도 힘든 일입니다. 다행히 모질라 커뮤니티에는 업계 최고의 개발팀, QA팀, 보안팀이 모여 있습니다.

이 글은 필자가 견습생 입장에서 모질라 최고의 엔지니어들로부터 한 수 배우기 위해 마련한 인터뷰 시리즈의 두번째 기사입니다.

Brian Warner를 소개합니다

제 매니저와 제가 처음 이 프로젝트를 기획했을 때, 맨 먼저 인터뷰하고 싶었던 인물이 Brian이었습니다. Brian은 몰랐겠지만, 그는 제가 처음 모질라에서 일 할 때부터 마음 속으로 따랐던 비공식적인 멘토였습니다. 그는 뛰어난 선생님이며, 보안 문제를 쉽게 해결하는 특별한 능력을 갖고 있는 전문가입니다.

모질라 안에서 Brian은 “예전” 파이어폭스 싱크(Sync)의 페어링(pairing) 프로토콜을 설계했고, “현재” 파이폭스 싱크의 프로토콜을 설계했으며, 페르소나(Persona) 인증체계의 보안 유지에 관한 핵심 역할을 수행했습니다. 모질라 밖에서 Brian은 Tahoe-LAFS 프로젝트를 공동으로 시작했으며 Buildbot 도구를 만들었습니다.

모질라에서 어떤 일을 하시나요?

제 직책은 클라우드 서비스 그룹의 시큐리티 엔지니어입니다. 저는 패스워드 같은 계정 정보를 안전하게 관리하는 프로토콜을 분석하고 개발합니다. 또 그런 프로토콜을 다양한 형태로 구현합니다. 그리고 다른 사람들의 코드를 리뷰하기도 합니다. 외부 프로젝트들도 관찰합니다. 외부 프로젝트들이 연동해도 좋을지 판단하기 위해서입니다. 그리고 저는 보안 문제(security failure)에 관한 많은 정보를 습득하려고 노력합니다. 예를 들면 0-days 문제, 현실세계에서 일어날 수 있는 다양한 위협, 우리가 사용할 도구와 알고리즘 등을 연구합니다.

UX vs Security: 이런 도식은 잘못된 이분법일까요? 보안이 훌륭하려면, 사용하기 불편해야 한다고 생각하는 사람들도 있습니다.

한때 저는 보안을 3가지 측면에서 절충해야 하는 문제라고 생각했습니다. x축, y축, 그리고 0을 지나지 않는 대각선에서 끝나는 문제가 아니라, 경우에 따라서는 제 3의 측면을 고려해야 하는 문제라고 생각했습니다. 세번째 축은 당신이 얼마나 많은 일을 할 수 있는지, 또는 당신이 얼마나 영리하게 일을 할 수 있는지, 또는 당신이 얼마나 자발적으로 사용자 설문과 실험을 수행할 수 있는지를 나타내는 척도입니다. 이것은 UX 전문가나 심리학자가 아닌 대부분의 엔지니어들이 무심히 지나치는 문제입니다. 저는, 믿음이라기 보다는 희망인데, 충분히 노력하면 안전하면서도 쓰기 쉬운 방법을 찾아낼 수 있을 거라고 믿습니다. 하지만 그러기 위해서는 아주 많이 노력해야 합니다.

요점은 사람들이 하고자 하는 일을 알아낸 다음 사람들이 내려야 하는 보안에 관한 모든 결정을 정상적인 업무 흐름으로 표현하는 것입니다. 당신이 휴가를 떠나면서 화분 보살피는 일을 부탁하기 위해 이웃에게 집 열쇠를 빌려준다고 가정합시다. 이때, 당신은 이웃에게 어떤 권한을 전달한 것인지 분명하게 인식할 겁니다.

이런 종류의 일에는 어떤 사회적 합의가 있습니다. 예를 들면 이런 것입니다. “나는 당신이 이 열쇠를 복제할 거라고 생각하지 않습니다. 그러니 내가 당신으로부터 열쇠를 회수하면 당신은 내가 부여했던 권한을 더이상 사용할 수 없을 것입니다.” 컴퓨터를 사용하지 않는 실생활 속의 행동과 사물에는 관습이라는 패턴이 있습니다. 비결이 있다면 그런 관습과 패턴을 이용하는 것입니다. 사람들이 실생활 속의 익숙한 패턴을 기대할 거라고 가정하고 컴퓨터 업무를 그런 패턴과 비슷하게 만드는 것입니다.

문제는 사람들에게 아주 부자연스러운 요구를 할 때입니다. 더 나은 방식을 생각하거나 만드는 것은 아주 어렵습니다. 패스워드를 예로 들어 봅시다. 패스워드는 여러가지 이유로 좋지 않은 인증(authentication) 기술입니다. 그런 이유 중 하나는 대부분의 경우 어떤 권한을 행사하기 위해서는 대상이 누구던 간에 당신의 권한(패스워드)을 전달해야 한다는 점입니다. 이것은 흡사 “나는 당신에게 내가 비밀을 알고 있다는 사실을 증명할 수 있어요”…”좋아요, 비밀을 말해봐요.”와 같은 상황입니다. 여기에는 굉장히 많은 문제가 있습니다. 예를 들어 당신이 누구와 말하고 있는지 어떻게 확신할 수 있으며, 다른 누군가가 옅듣고 있지 않다고 어떻게 확신할 수 있겠습니까?

좋은 패스워드는 컴퓨터에 의해 랜덤하게 생성된 길이가 긴 패스워드입니다. 그런 패스워드를 암기하는 것은 분명 가능하기는 하겠지만 많은 연습과 노력이 필요할 것입니다. 그건 일개 프로그램이 요구하기에는 지나친 일입니다.

하지만, 만약 당신에게 그런 종류의 (랜덤하게 생성된 길이가 긴) 패스워드가 한개만 있고 그 패스워드를 당신 폰(phone)에서만 사용한다고 가정해봅시다. 그러면 이제 당신의 폰이 보안에 관련된 모든 인증을 관리하는 매개물이 됩니다. 그정도는 (사용자에게 어려운 패스워드를 기억하라고 요구하는 것보다는) 적절한 수준의 요구입니다. 이제 당신의 폰이 당신의 인증 수단입니다. 폰은 사람보다 (패스워드를) 잘 기억합니다. 이제 시스템을 이용하기 위해 필요한 것은 핸드폰 손잡이 뿐입니다.

어떤 상황에서는 그정도로 충분할 것입니다. 하지만 아주 드문 특별한 상황에서는 좀더 높은 강도의 보안이 필요합니다. 당신에게는 매일 수행하는 간단하고 대수롭지 않은 많은 일들이 있습니다. 당신은 폰을 잃어버렸을 때만 보다 복잡한 인증 방법으로 돌아가면 됩니다. 마치 지갑에 충분한 현금을 가지고 다니다가, 아주 드물게만 은행을 찾아가서 예금을 인출하는 것과 같습니다.

제 생각엔 이렇게 처리하는 것이 충분히 가능하다고 생각합니다. 하지만 대부분 나쁜 패턴으로 일을 처리하곤 합니다. 그러니까 사용자에게 충분한 정보를 제공하지 않고 엄청난 양의 선택을 요구하면서 사용자를 탓하는 패턴 말입니다. 이렇게 강요하는 선택 중에는 의미 없는 것들도 많습니다.

당신은 많은 사용자들이 자신에게 요구된 선택의 내용과 영향을 이해하지 못한다고 생각하나요?

예, 분명 그렇다고 생각합니다. 그리고 선택을 요구하는 질문이 대부분 적절하지 않다고 생각합니다. 이건 불공정한 처사입니다. 누군가에게 다가가 불편한 상황을 강요하는 것은 – X입니까? Y입니까? – 약간 잔인합니다.

생각나는 또다른 예로 권한요청 다이얼로그가 있습니다. 특히 윈도(Windows) 박스에서 표시되는 다이얼로그들 말입니다. 권한요청 다이얼로그는 아주 단순한 작업을 할 때도 표시됩니다. 특이하고 위험한 일을 할 때만 표시되는 것이 아닙니다. 권한요청 다이얼로그는 당신의 허락을 구하는 것처럼 위장하고 있지만, 다이얼로그가 표시된 맥락이나, 이유, 파급효과를 충분히 설명하지 않습니다. 즉 진짜 질문이 아닙니다. 권한요청 다이얼로그는 협박 또는 최후의 통첩입니다. 만약 당신이 “아니오”라고 대답한다면 당신은 아무 일도 완료할 수 없습니다. 만약 “예”라고 대답하면 시스템은 “뭔가 나쁜 일이 일어날텐데 그건 전부 당신 탓”이라고 말합니다.

원래 권한요청 다이얼로그는 사용자에게 상황을 알리고 선택할 수 있는 기회를 주는 것이 목적입니다. 하지만 지금처럼 사용되는 것은 사용자 탓하기, 희생자 탓하기 패턴입니다. “뭔가 나쁜 일이 일어날 겁니다. 하지만 당신이 OK 버튼을 눌렀기 때문에 당신이 책임져야 합니다.”라는 것이죠. 사용자는 어떤 일을 선택하기에 충분한 정보를 갖지 못합니다. 시스템이 보안상 취약함 없이 요구된 일을 처리할 수 있을만큼 잘 설계되지 못한 탓입니다.

몇 달 전 “새로운” 싱크(Sync)가 세상에 나왔습니다. 당신은 공개된 포럼과 회의를 통해서 격렬한 토론 끝에 씽크 프로토콜을 만들었습니다. 이것은 보안 방식을 감춤으로써 보안을 유지하는 정책과는 정반대의 시도입니다. 당신의 의도했던 바는 무엇이었나요?

토론을 하면서 제가 기대했던 것은 두가지 입니다. 저는 싱크 프로토콜에 관한 모든 것을 설명하고 공개적으로 토론했습니다. 왜냐하면 그게 옳은 일이었으니까요. 그게 우리가 소프트웨어를 개발하는 방식입니다. 그게 오픈소스 방식이죠. 저는 다른 식으로 개발하는 것은 상상할 수 없었습니다.

모든 것을 공개하면서 기대했던 것은 사람들의 피드백이었습니다. 사람들이 기초적인 설계상의 약점을 지적해주기 바랬습니다. 저는 사람들이 보안 방식을 편안하게 느끼면 좋겠다고 생각했습니다. 왜냐하면 새로운 싱크가 기존 보안 방식을 바꿨기 때문입니다. 우리는 페어링(pairing) 과정을 없애고 대신 패스워드를 기반으로 싱크가 일어나도록 바꿨습니다. 저는 사람들이 그런 변화가 무엇을 의미하는지 그리고 우리가 왜 그런 시도를 했는지 시간을 갖고 이해해주기 바랬습니다. 우리는 설계 원칙과 현실적 제약들을 공개하고 목표를 달성하기 위해 패스워드 방식으로 변경할 수 밖에 없었던 이유를 사람들이 납득해주기 바랬습니다. 그리고 패스워드 기반으로 달성할 수 있는 최선의 보안 방식이 어떤 것인지 생각해주기 바랬습니다.

그리고 다른 이유가 있다면, 그렇게 공개적으로 토론하면서 가능한 많은 전문가들로부터 조언을 받는 것이 제가 아는, 옳바르고 깨지지 않는 확실한 코드를 만드는 유일한 방법이었습니다.

그러니까 검토하는 사람은 많을수록 좋죠…

프로토콜이나 API를 설계하는 사람이 자리에 앉아 스펙이나 코드를 작성하기 전에 생각해야 할 것은 무엇일까요?

사용자의 요구를 생각하라고 말하고 싶습니다. 사용자들이 달성하고자 하는 바를 가장 미니멀(minimal)하고 가장 기본적인 형태로 정제해야 합니다. 가장 적은 양의 코드와 가장 적은 양의 노력으로 사용자의 요구를 만족시킬 수 있는 방법을 찾아야 합니다.

마치 프로토콜 개발의 애자일 버전 같군요.

그렇죠. 미니멀리즘은 확실히 유용합니다. 일단 무언가 할 수 있는 기본적인 API가 있다면, 그 API로 할 수 있는 온갖 나쁜 일들을 생각해보세요. 그런 나쁜 일들을 방지할 수 있는 방법을 시도하고 만드세요. 아니면 그런 나쁜 일들을 하려면 가능한 큰 대가를 치르도록 만드세요.

보안에 관한 어려운 문제가 있습니다. 때때로 당신은 “X라는 문제가 발생할 확률은 얼마인가?”라고 묻습니다. 만약 당신이 무엇인가를 설계를 했고 거기에서 어떤 문제가 발생할 확률이 1/1000 이라고 합시다. 어떤 특정한 입력값 때문에 이런 문제가 발생한다고 가정합시다. 만약 이런 문제가 정말 무작위적으로 발생하는 거라면 1/1000 확률 정도는 허용할 수 있습니다. 1/1M 확률도 받아들일 수 있습니다. 하지만 해커(attacker)가 입력값을 조정할 수 있다면, 그건 더이상 1/1000 확률이 아닙니다. 수치적으로는 1/1000 보다 훨씬 적은 확률이라고 하더라도, 해커는 그 문제를 반드시 발생하게 만들겁니다.

이건 누가 더 똑똑하고 누가 더 철저한가를 겨루는 게임입니다. 일어날 수 있는 모든 일들과 있을 수 있는 모든 상태를 식별하기 위해 시스템을 분석하는 것은 무척 고된 일입니다. 하지만 누군가 결함을 찾는 사람들이 있다면, 그들이 하는 일 역시 시스템 분석입니다. 만약 그들이 당신보다 더 철저하다면, 그들은 당신이 보호하는데 실패한 문제점을 발견할 것입니다.

바로 그것이 위협 모델링(threat modeling)인가요?

그래요. 사람마다 그 용어를 다른 의미로 사용하지요. 당신은 시스템을 설계할 때 기본 원칙들을 설정합니다. 당신은 앞으로 펼쳐질 게임을 가정합니다. 그 게임에서 Alice는 패스워드를 정하고, Bob은 그녀의 패스워드를 추측하려고 노력한다고 가정하지요. 뭐 그런 종류의 가정 말입니다.

당신은 기본 원칙들을 정할 것입니다. 어떨 때는 원칙에 의하면 … 해커(attacker)는 방어 시스템에 접근하지 못합니다. 해커는 단지 어떤 API를 통해서만 접근할 수 있습니다. 그리고 그 API는 당신이 모든 선량한 사람들에게도 제공하는 API입니다. 하지만 당신은 선량한 사람과 나쁜 사람을 구별할 방법이 없습니다. 그들은 같은 API를 사용할 것입니다.

그러면 당신은 보안에 관련된 속성들을 조사합니다. 만약 해커가 할 수 있는 유일한 일이 API를 호출하는 것이라면, 아마도 해커는 API 호출을 통해서 패스워드를 추측하려고 시도하거나, 당신이 예상하지 못했던 입력 데이터를 전달해서 버퍼 오버플로우를 유발시키려고 시도하겠지요.

이제 당신은 한발 뒤로 물러서서 말합니다. “그래, 여기서 가정하고 있는 것은 무엇이지? 그 가정이 정말 유효할까?” 당신은 패스워드를 데이터베이스에 저장했습니다. 해커가 데이터베이스를 볼 수 없다고 가정했기 때문입니다. 그런데 시스템의 다른 부분이 잘못되면, 이런, 이제 해커가 데이터베이스를 볼 수 있군요. 그래요, 가정을 철회합시다. 이제 당신은 대부분의 해커는 데이터베이스를 보지 못하지만, 드물게는 볼 수 있다고 가정을 바꿉니다. 이제 어떻게 해야 데이터베이스에 있는 정보를 가장 안전하게 보호할 수 있을지 생각해야 합니다.

“당신이 막고자 하는 위협은 모두 어떤 것들인가요?”라는 문제를 생각해봅시다. 때때로 당신은 모래에 금을 긋고 말합니다. “이 수준까지는 모든 위협을 방어할 것입니다. 하지만 이 수준을 넘으면 책임질 수 없습니다.” 이것은 실용적인 관점에서 “그 위협을 막을 수는 있지만 그럴려면 개발 비용이 5배 더 필요합니다.”라고 말하는 것과 같습니다.

때때로 사람들은 해커가 느끼는 가치와 사용자가 지불하는 비용을 평가합니다. 그것은 기대 가치에 근거한 일종의 보험 모델입니다. 해커가 무슨 일을 달성하려면 X의 비용을 지불해야 할 것입니다. 그리고 해커는 체포되는 위험을 감수하면서 그 일을 달성했을 때 Y의 수익을 기대할 수 있을 것입니다.

이럴 때 우리는 나쁜 일보다는 좋은 일을 할 때 인센티브를 얻도록 시스템을 재정비할 수 있습니다. 비트코인(Bitcoin)은 이런 측면에서 아주 주의 깊게 설계된 시스템입니다. 비트코인 시스템에서는 해커가 나쁜 의도를 갖고 이중지불(double spend)을 시도함으로써 시스템에 해를 끼칠 수 있습니다. 하지만, 분명한 것은 해커를 포함한 모든 사람이 시스템에 이로운 일을 할 때 더 많은 이득을 얻을 수 있다는 것입니다. 사람들은 시스템에 해로운 일을 할 때보다 이로운 일을 할 때 더 많은 돈을 벌 수 있습니다. 그래서 이성적인 해커라면 더이상 해커 일을 하지 않을 것입니다. 대신 선량한 참여자가 될 것입니다.

시스템 설계자가 시스템이 적절한 수준의 안전성을 갖도록 개발하는 가장 좋은 방법은 무엇일까요?

내 생각에 가장 좋은 지침은 최소 권한 원칙(POLA: Principle of Least Authority)입니다. 종종 POLA라고 표현합니다. 모든 컴포넌트는 그 컴포넌트가 하기로 계획된 작업을 하는데 꼭 필요한 정도의 권한만 가져야 합니다. 여기에는 여러가지 의도가 담겨있습니다. 그중 하나는 당신의 시스템을 여러개의 분리되고 격리된 컴포넌트들로 구성해서, 임의의 한 컴포넌트가 이상해지거나, 오염되거나, 버그로 인해 의도치 않은 동작을 하더라도 그 피해가 파급되지 않도록 만드는 것입니다.

저는 압축해제 루틴을 자주 예로 듭니다. gzip 같은 것 말이죠. 한 쪽 선으로 압축된 데이터(bytes)가 들어옵니다. 데이터 프로세싱 작업을 수행하기 전에 당신은 압축 데이터를 풀어야 합니다. 소프트웨어 컴포넌트로 표시하자면, 2개의 선을 가진 격리된 모듈입니다. 한 쪽 선으로는 압축 데이터가 입력되고 다른 쪽 선으로는 압축이 해제된 데이터가 출력됩니다. 이 모듈은 메모리를 할당하고, 압축 포맷을 처리하고, 조회 테이블을 만드는 등의 일을 할 것입니다. 하지만 그게 전부입니다. 입력 데이터가 아무리 이상하고, 이 모듈이 아무리 나쁜 의도로 만들어졌어도, 이 모듈이 할 수 있는 것은 다른 쪽 선으로 데이터를 뱉어내는 일 뿐입니다.

이것은 유닉스가 프로세스(process)를 격리시키는 것과 조금 비슷합니다. 프로세스가 시스템콜(syscall)을 통해 전체 디스크를 날리거나, 네트워크 트래픽을 유발하는 등 모든 일을 할 수 있다는 점만 제외하면 말이죠. 이 모듈은 단지 입력 파이프 하나와 출력 파이프 하나만 가지고 있습니다. 그게 전부입니다. 이런 식으로 코드를 만드는 것이 언제나 쉬운 것은 아닙니다. 어쨌든 이런 식의 코딩이 좋습니다. 이건 정말 좋은 엔지니어링 습관입니다. 왜냐하면 이렇게 하면 당신이 어떤 코드의 파급 효과를 알아보려고 할 때 바로 그 코드에 관련된 부분만 보면 되기 때문입니다. 이것이 바로 우리가 전역 변수를 싫어하는 이유입니다. 그리고 우리가 객체지향 설계를 좋아하는 이유입니다. 객체지향 설계에서는 클래스의 인스턴스가 자신의 내부 상태를 감출 수 있습니다. 적어도 다른 객체의 내부 상태를 함부로 찔러보면 안된다는 강한 관습이 존재합니다. 사적인(private) 상태를 가질 수 있다는 것은 사적인 속성을 가질 수 있다는 말이며, 이것은 당신이 예측할 수 없는 잠재적인 파급효과를 걱정하지 않고 어떤 작업의 수행 계획을 세울 수 있다는 것을 의미합니다. 그렇게 객체들을 격리시키면 소프트웨어가 좀 더 분석하기 쉬워집니다. 격리시키는 것의 장점은 메모리의 안전을 책임지는 언어(memory safe language)의 필요성과도 관계 있습니다…

메모리의 안전을 책임지지 않는 언어로 단단하게 뭉쳐진 큰 규모의 프로그램을 개발하면 신뢰성을 보장하기가 정말 힘듭니다. 그래서 저는 실행 속도면에서 손해를 보더라도 메모리의 안전을 책임지는 고수준 언어를 선택합니다. 대부분의 경우 우리는 그렇게 빠른 속도를 필요로 하지 않습니다. 속도가 필요하다면, 속도가 필요한 부분만 떼어내서 별도의 프로세스로 분리시키면 됩니다.

웹에서 이런 원칙을 깨는 문제들이 있다면 어떤 것이 있나요?

글쎄요, 웹은 특히 재미있는 공간입니다. 우리는 웹을 수신하는 쪽에서 메모리의 안전을 책임지는 언어를 사용하곤 합니다.

당신 말은 파이선이나 자바스크립트를 말하는거지요?

그래요. 그리고 우리는 보다 객체지향적인 개념을 사용하고 보다 격리된 환경을 사용합니다. 내가 웹에서 발견하는 큰 문제는 당신이 입력 데이터를 검증하고 보정하는데 실패하는 경우입니다. 그래서 위조 데이터 주입 공격(injection attack)을 허용하곤 합니다.

당신은 이미 작성된 구현물을 리뷰했던 많은 경험이 있습니다. 페르소나(Persona)가 하나의 예가될텐데요. 당신이 보기에 프론트엔드와 백엔드에 있는 일반적이 문제라면 무엇이 있을까요?

보통 문제를 회피하거나 어떤 가정을 만들려는 경향이 있습니다. 데이터가 어디서 오는지, 그리고 데이터가 잘못된 것으로 판별됐을 때 해커가 얼마나 큰 권한을 얻게되는지에 대해 가정을 만들려고 하는 것이 문제입니다.

그게 당신이 시스템 안에서 데이터의 흐름을 쉽게 추적할 수 있게 만들자고 주장하는 이유인가요?

예, 분명히 그렇습니다. 만약 코드를 줌아웃(zoom out)해서 여러 작은 컴포넌트들이 여러 작은 선들로 연결되어 동작하는 형태로 볼 수 있다면 좋을 것입니다. 그리고는 이렇게 말하는 거죠. “좋아요, 이 모듈이 어떻게 이런 문자열을 만들었죠?” 음, 이 문자열은 여기에서 나왔군요. 거기서 살펴 봅시다. 또 어디서부터 나온거죠? 그리고 출처를 찾아 추적합니다. 여기군요, 그 문자열은 사용자가 입력한 파라메터로부터 생겨난 것입니다. 그 문자열은 브라우저로부터 만들어졌습니다. 그리고 브라우저가 그 문자열로 postMessage 메시지를 보냈군요. 좋아요, 해커는 그런 데이터를 이용해서 얼마나 많은 권한을 얻게되나요? 해커는 어떤 일을 할 수 있죠? 그로 인해 우리가 위협을 느끼게될 까요? 그렇게 파악할 수 있다면, 당신은 어떤 주어진 지점에서 데이터의 타입이 무엇인지 분석하고, 데이터의 타입이 변경되는 지점을 확인하고, 적절한 보안조치에 실패한 지점이 있는지 알아낼 수 있습니다. 그렇게 타입 변환이 일어나거나 당신이 타입을 혼돈한 지점을 알아낼 수 있는 거죠. 분명한 것은 간결하고, 시각적이고, 추적 가능한 분석이 중요하다는 것입니다.

데이터 흐름 감시를 쉽게 만드는 방법이 있을까요?

제 생각에는, 서로 다른 코드들 사이의 상호작용을 최소화하는 것이 정말 중요합니다. 어떤 작업을 어떤 작은 영역에 격리시켜야 합니다. 전체 기능을 적절한 크기의 조각들로 분리시켜보세요.

종심방어(defence in depth)란 무엇인가요? 그리고 개발자들이 시스템에 어떻게 적용할 수 있나요?

“허리띠와 멜빵(Belt and suspenders)”이라는 고전적인 표현이 있습니다. 만약 하나가 잘못되더라도, 다른 하나가 당신을 보호할 것입니다. 허리띠와 멜빵을 모두 착용하면 우스꽝스럽게 보일 것입니다. 왜냐하면 허리띠와 멜빵은 당신의 바지를 고정시켜주는 별개의 도구니까요. 하지만 어떤 때는 허리띠가 고장나고, 어떤 때는 멜빵이 고장납니다. 두개를 모두 사용하면 바지가 벗겨져서 당황하는 일을 이중으로 막을 수 있습니다. 그래서 종심방어(defence in depth)란 통상 외곽방어(perimeter security)에만 의존하지 말라는 의미로 사용됩니다.

그말은 시스템 전체에 걸쳐 데이터를 체크해야 한다는 뜻인가요?

이런 판단을 위해서는 항상 성능 비용이나 복잡성 비용을 따져야 합니다. 만약 당신의 코드가 결함 체크 코드로 가득하다면, 당신의 코드가 실제로 어떤 일을 하는지 보려고 하는 사람들의 가독성을 떨어뜨릴 것입니다. 그것은 당신의 코드를 이해하기 어렵게 만듭니다. 코드 가독성은 코드를 올바른 방식으로 올바른 조건에서 사용하게 하기 위해 중요합니다. 그래서, 항상 지나친 장황함과 지나친 간결함 사이에서 균형을 찾아야 합니다. 체크 코드를 얼마나 많이 사용할지 적절하게 판단해야 합니다.

외곽방어(perimeter security) 말인데요, 당신 프로그램 주변에 점선을 긋고 “나쁜 사람들은 이 금 밖에 있습니다. 금 안쪽에 있는 사람들은 모두 좋은 사람들입니다”라고 선언하는 것은 정말 빠지기 쉬운 함정입니다. 그렇게 선언하고는 방어 코드를 경계선에만 구현하고 내부에는 구현하지 않는 거죠. 어떤 이야기를 들은 적이 있는데 이런 판단을 하는 데는 진화적이고 생물학적이고 사회적인 이유가 있다고 합니다. 사람들이 부족 생활을 할 때 100명 내외의 부족 사람들하고만 친하게 지냈습니다. 바로 옆의 다른 부족도 아주 멀리 떨어져 살았죠. 이럴 때 당신은 전통에 따라 아는 사람들을 신뢰합니다. 그리고 모르는 사람들은 눈에 보이는 즉시 죽입니다.

한동안은 이런 규칙이 통용될 수 있습니다. 하지만 이런 방식으로는 100명 이상의 사회를 만들 수 없습니다. 우리는 컴퓨터 시대에도 그런 방식으로 생각합니다. 우리는 세상에 “나쁜 사람”과 “좋은 사람”이 있다고 생각합니다. 그래서 나쁜 사람만 막으면 된다고 생각합니다. 하지만 우리는 인터넷 상에서 나쁜 사람과 좋은 사람을 구별할 수 없습니다. 그리고 좋은 사람도 실수할 때가 있습니다. 그래서, 최소 권한 원칙이 중요합니다. 소프트웨어를 독립적인 컴포넌트들로 분리하고 각 컴포넌트들은 서로 아주 제한적인 접근만 하게 합니다. 그러면, 만약 어떤 컴포넌트가 누군가에 의해 오염되거나, 누군가 의도적으로 기대하지 않던 동작을 하게 하거나, 아니면 단지 버그가 있었거나 하더라도 그 피해가 확산되지 않을 수 있습니다. 왜냐하면 그 옆의 컴포넌트가 훼손된 컴포넌트 맘대로 움직이지 않을 것이기 때문입니다.

당신 스스로 만들었거나 다른 사람이 만든 코드 중에서 특별히 잘만들어져서 다른 사람들이 보고 배울만한 코드가 있나요?

하나 있습니다. 제가 Tahoe-LAFS 프로젝트를 위해 만든 핵심 공유조각-다운로드 루프입니다.

Tahoe 프로젝트는 파일들을 다소 중복되는 여러개의 “공유조각(shares)”들로 업로드 합니다. 이 공유조각들은 여러 개의 서버로 분산됩니다. 나중에, 당신이 그 파일을 다운로드 받고자 할 때, 당신은 공유조각들 중 일부만 받으면 됩니다. 그래서 몇몇 서버가 죽더라도 문제가 되지 않을 수 있습니다.

그 공유조각들은 아주 많은 무결성-보호를 위한 Merkle 해시트리(hash trees)를 갖고 있습니다. 이 해시트리가 당신이 다운로드한 데이터의 검증을 돕습니다. 이 해시(hash)들의 위치를 언제나 미리 알 수 있는 것은 아닙니다 (우리는 레이아웃을 정확하게 규정하지 않았습니다. 그래서 구현체가 다르면 다른 레이아웃을 사용할수도 있습니다). 하지만 우리는 라운드-트립을 최소화해서 빠르게 다운로드 하는 것을 원했습니다. 그래서 우리는 해시트리의 위치를 추정하고 추정에 근거해서 해시트리를 가져오게 했습니다. 만약 잘못된 위치라고 판별되면, 우리는 두번째 시도를 하고 더 많은 데이터를 가져옵니다.

이 코드는 정말이지 최소한의 데이터만 가져오려고 노력합니다. 이 코드는 압축된 비트맵 집합을 이용합니다. 각 비트맵에는 우리가 가져오려고 하는 레코드의 바이트수를 기록합니다 (그 숫자가 맞기를 바랍니다). 하나의 숫자는 우리가 정말 필요로 하는 바이트 수입니다. 또 다른 숫자는 우리가 이미 가져온 바이트 수입니다. 그리고 우리는 알맞은 크기의 데이터를 요청하죠.

제가 못견딜 정도로 재밌어 하는 것은 이렇게 영리한 모듈의 전체 알고리즘이 롤링스톤즈 노래의 가사에서 나왔다는 점입니다. 저는 제가 다음과 같이 일을 시작한다고 생각합니다. “당신은 언제나 당신이 원하는 것을 가질 수 없어요. 하지만 언젠가는 … 당신이 원하는 것을 얻을거에요”, 그리고 거기서부터 다시 일이 반복되는 겁니다.

이 알고리즘에서 배울만한 또다른 것은 이것이 지나치게 영리하다는 점입니다. 우리가 이 코드를 만들고 난 다음, 우리는 이코드가 이전의 덜-복잡한 코드보다 약간 더 느리다는 것을 발견했습니다. (필요로하는 것보다 더 많은 데이터를 가져오더라도) 약간 더 큰 블록을 읽는 것이 아주 많은 수의 작은 조각을 읽는 것보다 빠르다는 것이 밝혀졌습니다 (네트워크와 디스크 입출력 오버헤드 때문입니다). 나는 대대적인 퍼포먼스 테스트를 실시해야 했습니다. 그리고 결심했죠. 다음부터는 노래 가사로부터 새로운 알고리즘을 만들어내기 전에 새로운 알고리즘의 속도를 측정하는 방법부터 만들어 놓겠다고 말이죠. :).

사람들에게 참여하라고 권하고 싶은 오픈소스 프로젝트로 어떤 것이 있나요?

개인적으로, 저는 보안 커뮤니케이션 도구에 관심이 많습니다. 그래서 저는 사람들( 특히 디자인과 UI/ UX 관련자들 )이 Pond, TextSecure 같은 도구들, 그리고 제가 만든 Petmail 프로젝트에 관심 가져주기를 희망합니다. 개인적으로 여러 다양한 run-your-own-server-at-home(당신-집에서-자기-서버를-운영하세요) 시스템들에 열광합니다. 예를 들면 GNU FreedomBox 같은 시스템 말이죠.

당신이 하는 일을 계속 지켜보려면 어떻게 해야 하나요?

GitHub 링크 https://github.com/warner에서 저의 커밋을 팔로잉하는 것이 좋을 것 같습니다. 제가 하는 거의 모든 일이 거기 공개됩니다.

Brian 고맙습니다.

대본이 있습니다.

저는 Brian과 기사 한 토막으로 다루기 어려울만큼 많은 이야기를 나눴습니다. GitHub에서 전체 대본을 볼 수 있습니다. 메모리의 안전을 책임지는 언어들, HTML을 사용해서 개발할 때의 암묵적인 형변환(type conversion), 그리고 Brian이 즐겨 쓰는 파이선 도구들에 대한 이야기들을 볼 수 있습니다.

다음은요!

다음 기사에는 Yvan Boiley와 Peter deHaan이 함께 등장합니다. Yvan은 Cloud Services Security Assurance 팀을 이끌고 있습니다. 그의 팀이 하고 있는 보안성 평가 업무와 일반 개발자가 자기 사이트의 문제점을 진단하기 위해 사용할 수 있는 도구들에 대해 토론하면서 보안을 주제로 한 이야기를 이어가려고 합니다.

Peter는 모질라의 빼어난 품질보증(QA) 엔지니어 중 한 명입니다. 그는 Firefox 계정 시스템의 안정성을 책임지고 있습니다. Peter는 경고 메시지에 대해, 프로젝트를 평가하기 위해 사용하는 프로세스와 도구에 대해, 그리고 사람들의 기분을 상하게 하지 않고 호되게 질책하는 비결에 대해 이야기할 것입니다.

작성자: ingeeKim

"누구에게나 평등하고 자유로운 웹"에 공감하는 직장인.

ingeeKim가 작성한 문서들…


댓글이 없습니다.

댓글 쓰기