스마트 계약에서 서비스 거부 (DOS) 공격을 방지하는 방법에 대해 대기열이 안전하고 소수점이 낮은 토큰을 처리하며 외부 통화를 안전하게 관리합니다.
Solodit 체크리스트 해상도 시리즈에 다시 오신 것을 환영합니다. 우리는 안전하고 탄력적 인 스마트 계약을 작성하기위한 실질적인 전략에 중점을 둔 Solodit Smart Contract Audit Checklist를 계속 탐색 할 것입니다.
이 체크리스트는 잠재적 인 취약점을 식별하고 사전 보안 조치를 구현하는 데 도움이됩니다. 이전 섹션 " Solodit 체크리스트 해상도 (1) "에서는 서비스 거부 (DOS) 공격과 관련된 3 개의 체크리스트 ( 추출 패턴, 최소 거래 금액 및 블랙리스트 )를 검사하고 개발자에게 솔루션을 제공했습니다. 아직 읽지 않았다면 계속하기 전에 기사를 확인하는 것이 좋습니다.
이 기사에서는 체크리스트에서 다른 세 가지 항목에 대해 논의하여 DOS 공격에 다시 집중합니다. 우리는 대기열 취급 취약점 , 소수점이 낮은 토큰으로 제기 된 문제 , 외부 계약 전화를 안전하게 처리하는 것의 중요성 으로 뛰어들 것입니다.
최상의 경험을 보려면 참조를 위해 Solodit 체크리스트 태그를 엽니 다.
오늘 우리가 논의 할 내용은 다음과 같습니다.
SOL-AM-DOSA-4 : 차단 대기열 처리 :이 문제는 공격자가 대기열을 조작하여 작업을 일시 중지하거나 방해하여 DOS를 초래할 때 발생합니다. 우리는 공격자가 처리 대기열을 파괴 할 수있는 방법을 살펴볼 것입니다.
Sol-Am-Dosa-5 : 낮은 소수점 토큰 : 소수점이 낮은 자리가있는 토큰을 다룰 때 발생하는 문제. 계산, 특히 분할은 0으로 잘라서 예상치 못한 해로운 행동을 초래할 수 있습니다. 이러한 저지금 토큰은 정수 부서에 문제를 일으킬 수 있으므로 주요 기능을 방해 할 수 있습니다.
Sol-Am-Dosa-6 : 안전하지 않은 외부 통화 : 취약점을 만들기 위해 적절한 오류 처리없이 외부 계약에 의존하는 방법을 살펴 봅니다. 외부 통화 실패가 올바르게 처리되지 않으면 전체 계약이 롤백 될 수 있습니다.
실제 공격은 이러한 취약점이 발생할 수있는 잠재적 손상을 입증합니다. 이 프로젝트는 사소한 태만으로 인해 큰 손실을 입었습니다.
Solodit 체크리스트는 감사 결과, 취약점 현상금 보고서 및 실제 이벤트를 기반으로합니다. 이러한 점검 목록을 연구하면 과거의 실수로부터 배우고 코드의 보안을 향상시킬 수 있습니다.
이제 샘플 코드를 통해 각 체크 항목을 하나씩 살펴 보겠습니다. 이러한 예제는 핵심 취약점을 강조하기 위해 단순화되었습니다.
문제 : 스마트 계약이 작업 처리를위한 대기열에 의존하는 경우, 공격자는 큐의 특정 상태를 조작하여 올바른 처리를 방지 할 수 있습니다.
체크리스트 질문 : "공격자가 서비스 중단을 유발하기 위해 대기열 처리를 차단하거나 방지 할 수 있습니까?"
솔루션 : 큐 취급 메커니즘에는 강력한 오류 처리 및 폴백 메커니즘이 필요하여 문제가 발생하더라도 문제를 계속 처리 할 수 있도록해야합니다.
예 :
대기열 추출의 예를 고려하십시오.
사용자는 추출을 요청하고 일부 플래그는 요청이 활성화되어 있음을 나타냅니다.
공격자는 추출이 발생한 후 resetUserStatus
기능을 사용하여 다른 사용자의 동일한 작동을 방지 할 수 있습니다.
// 易受攻击的函数:可以被利用function resetUserStatus() external { // 任何人在仍然处于队列中的情况下都可以重置他们的状态withdrawalRequested[msg.sender] = false; // 注意:用户没有被移出队列! } // 处理队列中的下一次提取function processNextWithdrawal() external { require(withdrawalQueue.length > currentIndex, "没有可处理的提取"); // 获取下一次提取Withdrawal memory withdrawal = withdrawalQueue[currentIndex]; // 可被攻击者利用:此检查可能会被重置状态所攻击require(withdrawalRequested[withdrawal.user], "提取请求不再有效"); // 处理提取uint256 amount = withdrawal.amount; require(balances[withdrawal.user] >= amount, "余额不足"); // 更新余额balances[withdrawal.user] -= amount; // 重置提取请求withdrawalRequested[withdrawal.user] = false; // 发送资金(bool success, ) = payable(withdrawal.user).call{value:amount}(""); require(success, "资金发送失败"); // 移动到队列中的下一个currentIndex++; }
이를 활용하기 위해 공격자는 다음을 수행 할 수 있습니다.
resetUserStatus
기능을 호출하십시오.processNextWithdrawal
함수가 롤백되어 연속 DOS 공격이 발생합니다.구제책 :
withdrawalRequested
상태를 수정하는 것을 제한합니다.문제 : 소수점 이외의 장소가있는 토큰은 정수 분열 문제를 일으켜 0으로 반올림 할 수 있습니다.
일정 기간 동안 토큰을 할당하는 토큰 스트리밍 계약을 상상해보십시오. 소수점이 낮은 정수 구분으로 인해 tokensPerSecond
0으로 반올림되면 할당 함수가 차단됩니다. 체크리스트 질문 : "낮은 소수점 토큰이 DOS로 이어 집니까?" 솔루션 : 반올림 오류로 인한 거래 프로세스의 중단을 방지하기 위해 소수점 이하 점수를 처리하는 논리를 구현하십시오. 예 :
특정 수의 토큰을 사용자에게 정기적으로 스트리밍하는 TokenStream
계약을 고려하십시오.
total_tokens
계약으로 이체해야합니다token_per_second
소수점이 1의 토큰을 사용하고 있기 때문에 0으로 반올림 될 수 있습니다.distributeTokens
기능이 롤백됩니다 contract TokenStream { IERC20 public token; uint256 public streamDuration; uint256 public tokensPerSecond; constructor(IERC20 _token, uint256 _streamDuration, uint256 _tokensPerSecond) { token = _token; streamDuration = _streamDuration; tokensPerSecond = _tokensPerSecond; } function distributeTokens(address recipient) external { uint256 balance = token.balanceOf(address(this)); uint256 amount = tokensPerSecond * streamDuration; uint256 tokensToSend = amount > balance ? balance : amount; require(tokensToSend > 0, "没有足够的代币进行流送"); token.transfer(recipient, tokensToSend); } } contract LowDecimalToken is ERC20 { constructor() ERC20("LowDecimalToken", "LDT") { _mint(msg.sender, 100000 * (10 ** decimals())); } function decimals() public view virtual override returns (uint8) { return 1; // 模拟小数点为低的代币} }
이 경우 TokenStreamTest
의 testDOSWithLowDecimalTokens
테스트가 롤백됩니다.
해결책 : 계약이 낮은 소수점 토큰을 올바르게 처리하고 수학 공식을 확장하여 계산 프로세스 중 정수를 반올림하여 발생하는 문제를 완화하십시오 .
문제 : 많은 스마트 계약은 외부 계약에 의존하여 상호 작용합니다. 외부 계약의 예기치 않은 동작으로 인해 전체 시스템이 롤백 될 수 있습니다 . 이러한 외부 오류를 처리하지 않으면 DOS 취약점이 발생할 수 있습니다.
체크리스트 질문 : "프로토콜이 외부 계약 상호 작용을 안전하게 처리합니까?"
솔루션 : 외부 계약의 성능에 관계없이 프로토콜 무결성을 보호하기 위해 외부 계약 상호 작용에 대한 강력한 오류 처리를 보장하십시오.
예 : 외부 체인 링크 가격 데이터 소스와 상호 작용하는 계약을 고려하십시오. 적절한 오류 처리를 위해 Try/Catch를 사용하지 않으면 외부 데이터 소스의 롤백이 우수한 것으로 전파되어 계약이 롤백으로 발생합니다.
getPrice
기능은 가격 데이터를 검색합니다.calculateSomethingImportant
함수는 getPrice
에 따라 달라지며 롤백됩니다. contract PriceDependentContract { AggregatorV3Interface public priceFeed; constructor(address _priceFeed) { priceFeed = AggregatorV3Interface(_priceFeed); } // 易受攻击的函数,在没有处理可能的Chainlink 回滚的情况下获取价格function getPrice() public view returns (uint256) { (, int256 price, , , ) = priceFeed.latestRoundData(); // 易受攻击的行:没有错误处理require(price > 0, "价格必须为正"); return uint256(price); } function calculateSomethingImportant() public view returns (uint256) { uint256 price = getPrice(); // ... 使用价格的一些重要计算return price * 2; }
해결 방법 : 롤백 오류를 처리하고 롤백 또는 캐시 값을 구현하기 위해 외부 계약 전화를 시도/캐치 블록으로 랩합니다 .
참고 : 외부 계약이 의도적으로 가스를 소비하는 에지 케이스가 있으며, 이는 캐치 블록을 실패시킬 수 있습니다! 나중에 이것에 대해 논의하겠습니다.
우리는 스마트 계약의 DOS 공격에 저항하는 능력을 향상시키기 위해 설계된 세 가지 주요 점검을 탐구합니다. 대기열 취급 취약점 , 소수점이 낮은 토큰과 관련된 문제 , 외부 계약 상호 작용을 안전하게 처리하는 것의 중요성 .
제공된 예는 핵심 취약점을 설명하기위한 것임을 기억하십시오. 기본 원칙을 이해 하고 이러한 개념을 특정 사용 사례에 조정하는 것이 매우 중요합니다.
이러한 제안을 구현함으로써 스마트 계약의 보안 및 탄력성을 크게 향상시킬 수 있습니다.
Solodit 체크리스트 해상도 시리즈의 다음 부분을 계속 지켜봐 주시기 바랍니다.
- 원본 링크 : cyfrin.io/blog/solodit-c ...
- Denglian Community AI Assistant는 모든 사람을위한 훌륭한 영어 기사를 번역합니다. 번역이 이해할 수없는 영역이 있다면 용서 해주세요 ~