Node.js 보안. 공홈의 Security Best Practices 문서 읽어보기
Security Best Practices 문서가 있어 읽어보았다. 신기한 내용만 추려보자면, Information Exposure through Timing Attacks (CWE-208) 값을 단순 비교(a === b)할 때, 문자열을 앞에서부터 한글자씩 비교하게 되면서 발생하는 시간차를 이용한다는 것 같다. 대체 뭘까 궁금해서 ChatGPT에게 설명을 요청해 받아낸 내용- - 서버가 클라이언트가 보낸 비밀(비밀번호, 토큰 등) 을 처리할 때 처리 시간이 입력값에 따라 달라지면 공격자가 여러 요청을 보내 응답시간을 통계적으로 비교하여 내부 비밀의 일부 정보를 유추할 수 있습니다. - 예: 문자열 단순 비교 (===)는 앞부분부터 비교를 하고 첫 불일치에서 바로 반환되므로 접두사가 맞을수록(비교가 길게 지속될수록) 응답 시간이 길어지는 경향이 있습니다. 공격자는 한 글자씩 맞춰가며(브루트포스/차례대로) 시간이 더 긴 입력을 고르면 정답에 가까운 문자임을 추측할 수 있습니다. - 특히 동일한 서버(혹은 같은 호스트)에서 타이밍 잡기가 쉬운 환경(공유 호스트, 로컬 네트워크, VM co-resident 등)에서는 성공 확률이 높습니다. - 또 한 가지 실수: 사용자가 없을 때와 있을 때 처리 시간을 달리하면(예: DB 조회 후 곧바로 실패 반환 vs 존재하면 해시 비교) 사용자 존재 여부 자체를 노출시킬 수 있습니다. 이를 이용한 정보 수집도 위험합니다. GPT가 제시해준 해결책 - 길이가 고정된(또는 비교 전에 고정 길이로 변환한) 바이너리 값들을 비교하고, crypto.timingSafeEqual을 사용해 비교한다. - 비밀번호는 평문이 아니라 KDF(scrypt, bcrypt, argon2 등) 로 처리한 고정 길이 해시(또는 키)를 저장하고 비교한다. - 사용자 존재 여부에 따라 처리 시간을 달리하지 않도록 — 사용자가 없을 때도 동일한 KDF 연산(더미 값)이나 timing-safe 비교를 수행해 시간 차를 줄인다. - 비교 전에 반드시 두 버퍼 길이가 같은지 확인(다르면 길이를 맞추거나 실패 처리) — timingSafeEqual은 길이가 다르면 예외가 날 수 있음. - 브랜칭(조건문)으로 비밀값을 분기하지 않도록 주의. Prototype Pollution Attacks (CWE-1321) javascript 내장 객체의 prototype 내용물을 바꿔치는 과정에 문제가 될 수 있었나보다. lodash에만 해도 CVE에 관련 취약점이 이미 몇 건 씩이나 보고되어 있다. 당연히 바뀔수있는 값 아닌가? 생각했는데, GPT가 아래와같은 사례일수 있다고 알려주었다. 공격자가 {"__proto__": {"isAdmin": true}}를 보내면 결과적으로 Object.prototype.isAdmin === true가 되고, 애플리케이션이 if (user.isAdmin) 같은 체크를 하면 공격자가 권한을 획득할 수 있습니다.
- 1more
