설명
사용자 입력이 util.format, console.log, sprintf 같은 포맷 문자열 위치에 들어가면 공격자가 %s, %d 같은 포맷 지정자를 삽입해 뒤따르는 인자를 의도와 다르게 해석하게 만들 수 있습니다. 보안 로그나 감사 로그에서 중요한 값을 숨기거나 왜곡하는 데 악용될 수 있습니다.
잠재적 영향
- 로그 메시지의 구조가 공격자 입력에 의해 바뀌어 감사 추적이 왜곡될 수 있습니다.
- 뒤따르는 인자가 공격자 지정 포맷에 의해 노출되거나 다른 의미로 기록될 수 있습니다.
- 보안 모니터링 규칙이 기대한 로그 형태를 찾지 못해 탐지가 어려워질 수 있습니다.
해결 방법
- 포맷 문자열은 상수로 고정하고 사용자 입력은 별도 인자로 전달하세요.
- 사용자 입력을 포맷 문자열에 결합해야 하는 경우 포맷 지정자 문자를 해당 포맷 API의 규칙에 따라 처리하세요. 가능하면 결합 자체를 피하세요.
- 구조화 로그를 사용해 메시지 템플릿과 사용자 값을 분리하세요.
예시
app, 인증된 req.user와 %s 형식을 지원하는 logger가 준비되어 있다는 전제의 발췌입니다. 고정된 포맷은 비밀 값 마스킹이나 줄바꿈 등 로그 내용의 처리를 대신하지 않습니다.
변경 전
javascript
const util = require("util");
app.get("/search", (req, res) => {
logger.info(util.format(req.query.message, req.user.email));
res.send("ok");
});
변경 후
javascript
app.get("/search", (req, res) => {
logger.info("search message=%s user=%s", req.query.message, req.user.email);
res.send("ok");
});
설명:
- 변경 전: 사용자 입력이 포맷 문자열 자체가 되어 뒤따르는 인자를 공격자가 제어한 방식으로 해석할 수 있습니다.
- 변경 후: 포맷 문자열을 상수로 고정하고 사용자 입력은 값 인자로 전달합니다.