Showing Posts From

빠졌는데요

'여기 인증이 빠졌는데요' - 개발팀이 싫어하는 문장 톱 3

'여기 인증이 빠졌는데요' - 개발팀이 싫어하는 문장 톱 3

"여기 인증이 빠졌는데요" - 개발팀이 싫어하는 문장 톱 3 오늘도 어김없이 오전 10시. 신규 API 보안 점검 중이다. POST 요청 날렸다. 토큰 없이. 200 OK 떴다. "아..." 이게 되면 안 되는 건데. 인증 헤더 빼고 다시 날렸다. 또 200 OK. 유저 정보 다 내려온다. 남의 거까지. 심장이 쿵 했다. 나쁜 의미로.슬랙 열었다. 개발팀 채널. "@김철수 API 인증 체크 부탁드립니다" 점잖게 썼다. 처음엔. 5분 뒤 답장. "어? 거기 인증 필요해요?" 필요하다. 매우. "네, 유저 정보 조회인데 인증 없이 호출 가능합니다" 또 5분. "아 그거요? 다음 스프린트에 넣을게요" 숨 참았다. 3초. "이거 지금 프로덕션인데, 남의 정보 다 보이는데..." "아 그래요? 근데 저 지금 급한 버그 픽싱 중이라..." 여기서부터 시작된다. 오늘의 전투. 1위: "여기 인증이 빠졌는데요" 6년 했다. 보안 QA. 이 문장 말하면 공기가 무거워진다. 개발자 표정이 굳는다. 매번. "인증이요...? 어디가요?" 다 알면서. "로그인 API에서 토큰 검증 안 하고 있습니다" "아..." 길게 늘어지는 '아'. 이게 시작이다. 반응은 보통 세 가지다. 첫 번째: 부정 단계 "그게 버그예요? 원래 그렇게 설계한 건데..." 아니다. 명세서 봤다. 인증 필수라고 써 있다. "명세서에 JWT 토큰 필수라고..." "아 그건 옛날 거고, 지금은 내부 API라서요" 내부? 인터넷에 열려 있는데? "퍼블릭 IP에서 호출 가능한데요" "아 그래요? 근데 URL 모르면 못 찾잖아요" URL이 보안이 되나. Obscurity는 보안이 아니다.두 번째: 협상 단계 "심각한 건 아니죠? P3 정도?" 심각하다. P1이다. "인증 없이 타인 정보 조회 가능하면 P1입니다" "어... 근데 실제로 악용된 사례는 없잖아요?" 없는 게 아니라 모르는 거다. 로그 분석 안 하니까. "로그 보면 알겠지만..." "로그요? 로그는 지금 안 보고 있는데..." 당연히. 세 번째: 지연 단계 "다음 주 배포 때 같이 넣을게요" 다음 주? 지금 뚫려 있는데? "핫픽스 가능할까요? 지금 취약점 열려 있어서..." "핫픽스요...? 그럼 배포 파이프라인 돌려야 하는데..." 그래야 한다. 보안 이슈니까. "CVSS 점수 8.2 나오는데요" 숫자 던졌다. 효과 있다. 가끔. "8.2요? 계산 어떻게 한 거예요?" 계산기 보여줬다. CVSS 계산기. Access Vector: Network Authentication: None Confidentiality Impact: High "아... 근데 저희 서비스 사용자가 적어서..." 사용자 수는 관계없다. 취약점은 취약점이다. 결국 타협했다. 내일 새벽 배포. 새벽 2시에 내가 테스트한다. 당연히. 2위: "이거 SQL Injection 되는데요" 이건 진짜 싫어한다. 개발자들. 왜냐면 '기초 중의 기초'니까. "부끄러운 거" 취급이다. 개발자 사이에서. 지난주에 찾았다. 검색 기능에서. GET /api/search?keyword=test' OR '1'='1500 에러 떴다. DB 에러 메시지 그대로. "MySQL syntax error near..." 심장이 또 쿵했다. 슬랙 DM 보냈다. 조용히. 이건 공개 채널에 쓰면 안 된다. 자존심 상한다. 개발자. "검색 API SQL Injection 취약점 있습니다. DM으로 상세 공유드릴게요" 읽음 표시 떴다. 2분 뒤. 답장은 30분 뒤. "확인했습니다. 근데 이거 관리자만 쓰는 기능이라..." 관리자도 해킹당한다. "관리자 계정도 타겟이 될 수 있어서요" "아... 근데 이미 Prepared Statement 쓰고 있는데..." 안 쓰고 있다. 코드 봤다. query = f"SELECT * FROM users WHERE name LIKE '%{keyword}%'"f-string 그대로. 교과서적 취약점. "코드 확인해보니 직접 문자열 조합하고 계시던데요" "아 그거요? 옛날 레거시 코드라..." 레거시면 더 위험하다. "고치기 어렵나요?" "어렵죠... 다른 데도 다 바꿔야 해서..." 얼마나 많길래. "몇 군데 정도?" "한... 20군데?" 20군데가 SQL Injection 가능하다고? 숨 참았다. 5초. "하나씩이라도 고쳐봐요. 일단 검색부터..." "네... 시간 나면..." 시간 나면은 안 한다는 뜻이다. 보통. 결국 JIRA 티켓 만들었다. P0로. CTO한테도 리포트 올렸다. 다음 날 핫픽스 나갔다. 역시 CTO. 개발자는 삐졌다. 일주일 동안. 점심 같이 안 먹자고 했다. 어쩔 수 없다. 보안이 먼저다.3위: "이 API 권한 체크가 없는데요" 이게 제일 미묘하다. 왜냐면 '작동은 한다'니까. 버그가 아니다. 기능 구현 누락이다. 근데 보안적으론 치명적이다. 지난달에 발견했다. 유저 삭제 API. DELETE /api/users/{user_id}로그인만 하면 된다. 누구나. 남의 계정도 지운다. 권한 체크 없으니까. 테스트했다. 내 계정 A로 로그인. 남의 계정 B를 삭제 요청. 204 No Content. 성공했다. "..." 슬랙 열었다. "@박영희 유저 삭제 API 권한 체크 필요합니다" 3분 만에 답장. 빠르다. "네? 권한이요?" "네, 지금 자기 계정 외에도 남의 계정 삭제 가능해요" "아 그거요? 원래 관리자용 API인데..." 관리자 체크 안 한다. 코드 봤다. "코드상 role 체크 없던데요" "어? 그래요? 근데 프론트에서 관리자만 버튼 보이게 해놨는데..." 프론트 제어는 보안이 아니다. curl 하나면 끝이다. "프론트 제어는 우회 가능해서요. 백엔드 체크 필요합니다" "아..." 또 길게 늘어지는 '아'. "근데 권한 체크 로직이 복잡해서... 시간이 좀..." 복잡하면 더 해야 한다. "IDOR 취약점이라 심각도 높습니다" "IDOR이 뭐예요?" 설명했다. Insecure Direct Object Reference. 객체 접근 권한 체크 안 하는 거. OWASP Top 10에 들어간다. "아... 그럼 언제까지 고쳐야 해요?" 이번 주. 가능하면 내일. "일주일 안에 가능할까요?" "일주일이요...? 다른 API도 다 체크해야 하는데..." 다 체크해야 맞다. "일단 삭제, 수정 API부터 점검해봐요" "네... 해볼게요..." 목소리에 힘이 없다. 2주 걸렸다. 결국. 20개 API 권한 체크 추가. 개발자는 지쳤다. 나도 지쳤다. 근데 해야 한다. 이게 우리 일이다. 개발자의 마음 이해한다. 어느 정도. 그들도 바쁘다. 매우. 기능 개발도 해야 하고. 버그 픽스도 쌓여 있고. 거기에 보안까지. "왜 이렇게 까다롭냐"고 한다. 가끔. 까다로운 게 아니다. 필수다. 해킹당하면 다 책임진다. 개발팀이. "보안팀 뭐했어?"도 들을 거다. 우리가. 그래서 미리 막는 거다. 근데 이게 충돌한다. 개발자의 우선순위:기능 개발 (PM이 독촉) 버그 수정 (유저 컴플레인) 성능 개선 (느리다고 항의) 보안 (음... 나중에?)보안 QA의 우선순위:취약점 수정 (지금 당장) 보안 강화 (예방) 기능은... 잘 모르겠고관점이 다르다. 개발자는 "될 때까지" 만든다. 우리는 "안 뚫릴 때까지" 뚫어본다. 방향이 반대다. 그래서 싸운다. 자주. 내가 하는 타협들 6년 하면서 배웠다. 말하는 방식이 중요하다는 것. 예전: "여기 인증 없는데요? 이거 왜 이래요?" 공격적이다. 비난처럼 들린다. 지금: "인증 체크 추가하면 더 안전할 것 같아요. 도움 드릴까요?" 부드럽다. 제안처럼 들린다. 효과가 다르다. 그리고 우선순위를 나눈다. P0: 지금 당장 (인증 누락, SQL Injection) P1: 이번 주 안에 (권한 체크) P2: 다음 스프린트 (보안 강화) P3: 여유 있을 때 (개선 사항) P0만 강하게 밀어붙인다. 나머지는 협상 가능하다. 그리고 직접 코드 짠다. 가능하면. "이렇게 고치면 될 것 같아요" PR 올린다. 리뷰 요청한다. 개발자가 좋아한다. 일이 줄어드니까. 같이 해결하는 거다. 싸우는 게 아니라. 그러면 관계가 좋아진다. 다음번에 또 취약점 보고할 때 덜 힘들다. 그래도 힘든 순간들 가끔은 진짜 화난다. 같은 취약점 반복될 때. "지난번에도 얘기했는데..." "아 그거요? 까먹었네요" 까먹을 일이 아닌데. 보안 가이드 문서 만들었다. 읽으라고 공유했다. 아무도 안 읽는다. "문서 어디 있어요?" 컨플루언스 첫 페이지다. "아 그거요? 나중에 볼게요" 나중은 오지 않는다. 그리고 사고 날 때. 실제 해킹 시도 있었다. DDoS는 아니고 credential stuffing. 로그인 시도 10만 건. 다행히 막았다. Rate limiting 있어서. 근데 그거 내가 추가한 거다. 3개월 전에. 그때도 "꼭 필요해요?"라고 물었다. 개발팀. 필요하다니까. 사고 후 회의. "다행히 보안 QA팀이 미리 조치해서..." 박수 받았다. 기분이 이상했다. 박수받을 일이 아닌데. 원래 있었어야 할 거니까. 그럼에도 계속하는 이유 취약점 찾았을 때. 희열이 있다. 정말. "이거다!" 심장 뛴다. 게임 깬 기분이다. 그리고 고쳐졌을 때. 다시 테스트한다. 인증 체크 들어갔다. 401 Unauthorized. 완벽하다. 뿌듯하다. 이 서비스가 조금 더 안전해졌다. 우리 유저들 정보가 지켜졌다. 밤에 잘 잔다. 마음 편히. CTF 대회 나갔다. 지난주. 1등 했다. Web 카테고리. 상금 100만원. 여자친구한테 자랑했다. "우리 남친 해커네~" 화이트 해커다. 강조했다. "맞아, 착한 해커" 기분 좋았다. 부모님한테도 말씀드렸다. "아들이 회사 보안 지키는 일 해요" "대단하네, 우리 아들" 뿌듯했다. 개발자들이랑 관계도 좋아졌다. 최근에. 술 먹었다. 회식에서. "야, 너 때문에 일 많아지긴 하는데..." 움찔했다. "고마워. 진짜로." "네?" "너가 안 잡아주면 우리가 욕먹잖아. 나중에." 인정받았다. 같이 일하는 거다. 결국. 적이 아니다. 동료다. 목표가 같다. 좋은 서비스 만들기. 앞으로의 계획 다음 달에 교육한다. 개발팀 대상 보안 교육. "Secure Coding 101" 준비 중이다. 자료. OWASP Top 10 중심으로. 실습도 넣을 거다. 직접 SQL Injection 해보기. 직접 XSS 공격 해보기. 체험하면 이해한다. 더 잘. 그리고 자동화 구축한다. CI/CD에 보안 스캔 넣기. SAST, DAST 돌리기. 커밋할 때마다 자동 체크. 내가 다 할 순 없으니까. 시스템이 해야 한다. 버그 바운티 프로그램도 열까 한다. 외부 화이트 해커들. 우리가 못 찾은 거 찾아주면. 포상금 주기. 더 안전해질 거다. CTO한테 제안할 거다. 다음 주. 오늘 마무리 6시다. 퇴근 시간. 근데 아직 못 끝냈다. 테스트. API 20개 더 남았다. 7시까지 해야겠다. 여자친구한테 문자 보냈다. "오늘 조금 늦을 것 같아. 저녁 먼저 먹어" "또? 무슨 취약점 찾았어?" "응, 인증 빠진 거" "개발자들 싫어하겠다 ㅋㅋ" 맞다. 근데 해야 한다. 이게 내 일이다. 화이트 해커. 좋은 해커. 서비스 지키는 사람. 모니터 3개 켰다. Burp Suite 실행. 다시 시작이다."여기 인증 빠졌는데요" 오늘도 말한다. 내일도 말할 거다.