2016년 방글라데시 중앙은행 사고의 핵심은, 탈취한 SWIFT 자격증명만 있으면 송금 지시가 진짜 은행이 보낸 것처럼 그대로 처리됐다는 점입니다. 같은 구조(정적 자격증명=영구 인증)를 재현하고, 고액·신규 목적지 송금에 대한 2차 승인(아웃오브밴드 확인)이 탈취된 자격증명만으로의 공격을 어떻게 막는지 검증했습니다.
메시지를 보낸 자격증명이 유효하다는 것만으로 그 내용 전체를 신뢰하는 금융 메시징 시스템을 만드는 백엔드 개발자용 학습 자료입니다.
정적 자격증명 하나만 맞으면 송금을 그대로 실행하는 취약한 메시징 API.
// 취약한 송금 메시징 API — 방글라데시 중앙은행 사고 모델링.
// 정적 자격증명 하나가 영구적인 "이 메시지는 진짜다" 증명으로
// 취급됨 — 탈취되면 그걸로 끝, 액수·목적지와 무관하게 통과.
class StaticCredentialTransfer {
constructor(validCredential) {
this.validCredential = validCredential;
}
transfer({ credential, amount, destination }) {
if (credential !== this.validCredential) {
return { status: 'invalid_credential' };
}
executeTransfer(amount, destination); // 액수·목적지 상관없이 실행
return { status: 'transfer_executed' };
}
}
module.exports = { StaticCredentialTransfer };
해결책: 자격증명이 맞아도 고액·신규 목적지 송금은 2차 승인 없이 거부한다.
// 해결책: 자격증명은 필요조건일 뿐, 충분조건이 아니게 만든다.
// 고액이거나 처음 보는 목적지면, 아웃오브밴드로 받은
// 1회용 승인코드가 추가로 있어야만 실행됨.
class SecondaryApprovalGuard {
constructor(validCredential, knownDestinations, largeAmountThreshold) {
this.validCredential = validCredential;
this.knownDestinations = knownDestinations; // Set<destination>
this.largeAmountThreshold = largeAmountThreshold;
}
transfer({ credential, amount, destination, approvalCode }) {
if (credential !== this.validCredential) {
return { status: 'invalid_credential' };
}
const isUnusual = amount >= this.largeAmountThreshold || !this.knownDestinations.has(destination);
if (isUnusual && !verifyOutOfBand(approvalCode)) {
return { status: 'secondary_approval_required' }; // 자격증명은 맞지만 부족
}
executeTransfer(amount, destination);
return { status: 'transfer_executed' };
}
}
module.exports = { SecondaryApprovalGuard };
이 상품에 대한 피드백이나 질문이 있으면 알려주세요. 회신을 원하시면 이메일을 남겨주세요(선택).