
트랜잭션 시뮬레이션: 서명하기 전에 그것이 무엇을 할지 보는 일
주소는 맞습니다. 금액도 맞습니다. 둘 다 확인했습니다. 그런데도 그 트랜잭션은 당신이 생각하는 그것이 아닙니다.
가정이 아닙니다. 신중한 사람이 얽힌 암호화폐 손실의 대부분이 바로 이 모양을 하고 있습니다. 누가 설득해서 낯선 사람에게 돈을 보낸 것이 아닙니다. 보이는 부분은 전부 옳고 결과만 전혀 다른 곳에 있던 무언가를 승인한 것입니다 — 토큰 지출 허용치 안에, 컨트랙트 호출 안에, 백 번은 본 주소의 한 글자 안에.
시뮬레이션은 그 틈을 메우려는 시도입니다. 당신의 서명이 그것을 현실로 만들기 전에, 트랜잭션의 내용이 아니라 효과를 보여 주는 일.
당신이 의도한 것과 당신이 서명하는 것 사이의 틈
트랜잭션은 문장이 아닙니다. 바이트입니다.
그 바이트가 단순한 송금일 때, 그것이 말하는 바와 실제로 하는 일 사이의 틈은 좁습니다. 주소 하나, 금액 하나, 수수료 하나. 그것이 컨트랙트 호출일 때, 틈은 엄청나게 벌어질 수 있습니다. approve는 허가처럼 보입니다. 그것은 다른 주소가 당신의 토큰을 옮길 수 있는 상시적인 권리이며, ERC-20 표준 아래에서 그 호출의 어느 부분도 얼마까지, 언제까지인지를 한정할 것을 요구하지 않습니다. 한 번 서명한 하나의 승인이 몇 달 뒤에 비워질 수 있습니다.
서명할 때 당신이 바라보는 화면은 그 바이트를 문장으로 번역해야 합니다. 그 번역이 곧 공격면입니다. 번역을 만드는 쪽이 당신의 서명을 원하는 쪽이라면, 거기에는 무엇이든 적을 수 있습니다.
예행연습이지, 약속이 아니다
시뮬레이션이란 트랜잭션을 방송하지 않은 채 체인의 현재 상태에 대고 실행해 보고, 무엇이 바뀌는지 기록하는 일입니다.
SSP Enterprise에서 이 일은 제안이 만들어질 때, 아무도 서명하기 전에 일어납니다. 시뮬레이션은 제안의 빌더가 만들어 낸 것 — 수신자, 금액, 토큰 컨트랙트, 그리고 SSP 자신이 조립한 호출 데이터 — 로부터 구성되며, 클라이언트가 건넨 원시 서명 hex로부터 만들어지는 일은 결코 없습니다. 읽기 전용으로 돌아갑니다. 세 개의 엔진이 서로 다른 체인 계열을 맡습니다.
- EVM 체인은 노드에 대고 읽기 전용 호출을 수행하고, 그로부터 생기는 잔액 변화와 디코딩된 호출을 되읽습니다.
- UTXO 체인은 노드가 아예 필요 없습니다. 입력과 출력은 이미 알려져 있으므로 이전과 이후는 선택된 코인들 위의 산술이고, 수신자는 당신에게 돌아오는 거스름돈인지 진짜 외부인지로 분류됩니다.
- 솔라나는 빌더가 만든 서명되지 않은 트랜잭션을 역직렬화한 뒤 네트워크 자체의
simulateTransaction을 서명 검증을 끈 채로 실행하고, 그 결과에서 볼트의 실행 전후 토큰 잔액을 읽어 냅니다.
돌아오는 것은 미리보기입니다. 각 자산의 잔액이 이전에 얼마였고 이후에 얼마가 될지, 그리고 — EVM에서는 — 그 호출이 실제로 무엇인지가 메서드와 인자로 디코딩된 모습으로.
두 가지는 아닙니다. 보증이 아닙니다. 체인의 상태는 움직이고, 제안 시점에 돌린 시뮬레이션은 그때의 체인을 찍은 사진입니다. 그리고 관문도 아닙니다. 설계에서 더 흥미로운 쪽이 바로 그 절반이고, 다시 돌아오겠습니다.
알려 줄 가치가 있는 열네 가지
숫자만 보여 주는 미리보기는 결국 문제를 당신이 알아보라고 요구합니다. 그래서 미리보기에는 경고가 따라붙고, 네 단계의 심각도로 열네 가지가 있습니다.
승인 — 가장 많은 지갑을 비워 온 범주입니다. 무제한이거나 상한이 없는 허용치는 심각입니다. 허용 목록에 없는 주소에 대한 0이 아닌 모든 지출 승인은 높음입니다. 그리고 컨트랙트가 아니라 사람이 소유한 계정을 승인하는 것도 높음인데, 그렇게 할 정당한 이유가 사실상 없기 때문입니다. 허용치를 쓰는 것은 컨트랙트이지 사람이 아닙니다.
수신자 — 조직의 연락처에도 볼트의 화이트리스트에도 없는 수신자는 표시됩니다. 당신의 볼트가 한 번도 보낸 적 없는 상대도 마찬가지입니다. 그 자체로는 둘 다 잘못이 아닙니다. 둘 다 한 번 더 읽어 볼 값어치가 있습니다.
컨트랙트 위험 — 소스가 검증되지 않은 목적지 컨트랙트, 최근 7일 안에 배포된 컨트랙트, 애초에 컨트랙트로 네이티브 가치를 보내는 일, 그리고 제공자가 노골적으로 악성이라고 표시한 모든 주소.
실행 — 시뮬레이션에서 트랜잭션이 되돌려지는 것. 곧 온체인에서도 실패하고 수수료를 낭비하리라는 뜻입니다. 또는 시뮬레이션된 유출이 제안이 내세운 금액과 맞지 않는 것. 볼트가 화면이 말하는 것보다 더, 또는 덜 잃는다는 뜻입니다.
성능 저하 — 그리고 분명하게 이름 붙은, 시뮬레이션이 아예 돌지 못한 경우. 닿지 않는 노드는 "사용할 수 없음"을 내놓지, 침묵이나 지어낸 무해 판정을 내놓지 않습니다.
그 심각도들 사이의 구분이 개수보다 더 중요합니다. 심각과 높음은 겉보기와 아마도 다른 트랜잭션에 관한 이야기입니다. 중간과 정보는 흔치 않은 트랜잭션에 관한 이야기이고, 정당한 트랜잭션도 이따금 흔치 않습니다.
주소 오염: 신중한 사람을 이기는 공격
경고 하나는 자기 절을 가질 자격이 있습니다. 거의 모든 보안 조언이 권하는 바로 그 습관을 겨냥하기 때문입니다.
주소 오염은 이렇게 작동합니다. 공격자가 당신이 이미 거래하는 어떤 주소와 앞 여섯 글자, 뒤 네 글자를 공유하도록 만들어 낸 주소에서 당신의 볼트로 아주 적거나 0인 트랜잭션을 보냅니다. 아무것도 도난당하지 않습니다. 사실 아무것도 행해지지조차 않습니다. 그 트랜잭션은 닮은 주소가 당신의 내역에 등장하게 하려고 존재합니다.
나중에 — 며칠 뒤, 같은 거래처에 다시 지불할 때 — 당신은 신중한 사람들이 그러듯 다시 입력하는 대신 자기 트랜잭션 내역에서 주소를 복사합니다. 신중한 사람들이 확인하듯 확인합니다. 앞의 몇 글자, 뒤의 몇 글자. 둘 다 맞습니다. 가운데는 맞지 않고, 돈이 가는 곳은 가운데입니다.
SSP는 제안의 모든 수신자를 볼트가 이미 아는 주소들과 대조합니다. 사람의 눈이 수행하는 바로 그 접두·접미 비교를 써서, 사칭당하고 있는 주소를 지목하는 심각 경고를 냅니다. 같은 확인이 들어오는 내역에 대해 반대 방향으로도 돌아가므로, 오염된 주소는 당신이 그것을 쓰려는 순간이 아니라 도착한 시점에 표시됩니다.
SSP를 결코 쓰지 않더라도 이 공격을 알아 둘 이유는 이렇습니다. 다른 모든 주소 공격을 막아 주는 그 확인 습관이야말로, 이 공격이 무너뜨리려고 만들어진 대상입니다. 주소는 통째로 비교하거나, 아니면 아무것도 비교하지 마십시오.
왜 경고를 서버에서 계산하는가 — 그러고도 왜 아무것도 막지 않는가
경고 집합은 서버 쪽에서 결정되며, 조직의 연락처와 볼트의 화이트리스트를 진실의 원천으로 삼습니다. 이것은 의도된 것입니다. 무엇이 허용된 것으로 치는지를 클라이언트가 정할 수 있다면, 침해된 클라이언트는 모든 것이 허용된 것이라고 조용히 정해 버릴 수 있습니다.
그런데도 그중 어느 것도 트랜잭션을 멈추지 못합니다. 시뮬레이션은 서명이나 방송의 조건이 되는 일이 결코 없습니다. 오류가 나거나, 시간이 초과되거나, 노드에 닿지 못한 제공자는 "사용할 수 없음"을 돌려주고, 제안은 온전히 서명 가능한 상태로 남습니다. 하위 시스템 전체가 장애로부터 격리되어 있어서, 미리보기의 고장이 제안을 좌초시키는 일은 결코 없습니다.
이상한 선택으로 들릴 테니 그 논리를 분명히 말해 두겠습니다. 막을 수 있는 미리보기는 막도록 만들 수 있는 미리보기입니다. 노드를 쓰러뜨려서, 거짓 심각을 만들어 내서, 소프트웨어가 잘못되는 천 가지 방식 중 어느 것으로든. 조언용 서비스가 아프다는 이유로 움직일 수 없는 자금은 이미 부분적으로 잃은 자금입니다. 돈을 지키는 것은 멀티시그의 임계값이고, 시뮬레이션은 열쇠를 쥔 사람들에게 알리기 위해 거기 있습니다. 무엇이 실제로 트랜잭션을 막는가가 이 논증의 긴 판본입니다.
서버와 당신의 기기가 어긋날 때
위의 모든 것은 서버의 읽기입니다. 당신의 기기는 자기 나름의 읽기를 합니다.

SSP Wallet이 서명할 제안을 당신에게 보여 줄 때, 그것은 바이트를 스스로 디코딩하고 자기가 찾아낸 것을 표시합니다 — 서버의 요약이 아니라. 그런 다음 둘을 견줍니다. 서버가 디코딩한 호출이 기기가 도출한 것과 다른 수신자 집합을 함의하면, 기기는 자기 몫의 심각한 불일치 경고를 내고 서버의 미리보기를 시각적으로 강등합니다.
권위를 갖는 것은 기기의 디코딩입니다. 이 확인은 일부러 보수적입니다. 서버 시뮬레이션이 없거나 대기 중인 것은 저하이지 모순이 아니며, 모순으로 보고되지 않습니다. 또한 서버가 애초에 디코딩된 호출을 만들어 내는 EVM 체인에만 적용됩니다. UTXO 체인에서는 견줄 대상이 없고, 기기 자신의 디코딩이 그저 홀로 섭니다.
어떤 지갑을 쓰든 가져갈 만한 성질이 이것입니다. 두 번째 의견은 첫 번째를 침해한 것과 같은 행위로는 침해될 수 없는 곳에서 올 때에만 값어치가 있습니다. 같은 서버에서 온 두 개의 요약은 하나의 요약입니다.
위험 표시줄을 무시하는 법을 배우지 않고 읽기
경고는 벽지가 되기 전까지만 효과가 있습니다. 몇 가지 습관이 그것을 쓸모 있게 지킵니다.
심각도를 먼저, 세부를 그다음에 읽으십시오. 심각과 높음은 멈춰 설 값어치가 있습니다. 새 공급업체에 대한 첫 지불에 붙은 중간이나 정보 경고는 시스템이 제대로 일하고 있다는 뜻이지 걱정할 이유가 아닙니다.
승인에 관한 경고는 무엇이든 완전한 정지로 대하십시오. 송금은 옮긴다고 말한 것을 옮깁니다. 승인은 트랜잭션보다 오래 사는 권리를 내줍니다. 상시적인 허가를 줄 생각이 아니었다면 답은 아니오입니다.
화면보다 기기를 믿으십시오. 둘이 어긋난다면, 당신 손에 있는 그 휴대폰이야말로 공격자가 따로 침해했어야 할 하드웨어 위에서 돌아가는 쪽입니다.
"사용할 수 없음"을 "괜찮음"으로 읽지 마십시오. 아무도 확인하지 않았다는 뜻입니다. 그것은 당신이 직접 더 주의 깊게 볼 이유이며, 금액이 크거나 평소와 다른 지불에서는 특히 그렇습니다.
여기의 모든 이야기는 서명 직전의 순간에 관한 것입니다. 그 뒤에 일어나는 일 — 누가 서명할 수 있는지, 몇 명이 필요한지, 어떤 조작이 두 기기를 다시 요구하는지 — 은 첫 기업용 볼트 설정하기와 중요 작업과 재서명에서 시작하십시오. 그리고 이 경고들이 그 둘레에 맞춰 빚어진 공격 유형에 대해서는, 암호화폐 사용자를 노리는 피싱 공격이 문제의 인간적인 절반을 다룹니다.


