스마트 컨트랙트 시큐리티 패턴
이전 포스팅에서
Checks Effects Interaction, Mutex Pattern
알아보고 재진입 공격에 대해서 포스팅을 하였습니다
이번엔 그밖에 다양한 시큐리티 패턴에 대해 알아보고자 합니다
1. Emergency Stop Pattern
- 블록체인에 배포된 스마트컨트랙트는 수정이 불가능합니다
그래서 예기치 못한 버그로 인해서 큰 피해를 줄 수 있는데 Emergency Stop Pattern은 특정 함수들이 실행되지 않도록 제어할 수 있도록 프로그래밍하는 패턴입니다. 쉽습니다
contract EmergencyStop is Owned {
bool public contractStopped = false;
modifier haltInEmergency {
require(contractStopped)
_;
}
modifier enableInEmergency {
require(!contractStopped)
_;
}
function toggleContractStopped() public onlyOwner {
contractStopped = !contractStopped;
}
function deposit() public payable haltInEmergency {
// some code
}
function withdraw() public view enableInEmergency {
// some code
}
}
컨트랙트의 Owner만이 function의 제어권을 조절할수있습니다.
haltInEmergency로 함수를 제어합니다 Owner만이 contractStopped의 변수값을 수정할 수 있습니다.
2. Speed Bump Pattern
- 과속 방지턱 패턴은 이름에서 알 수 있듯이 보행자를 보호하기 위한 안전장치입니다
Speed Bump Pattern은 특정 함수를 실행하기 위해서 의도적으로 시간을 지연시키거나 한 번에 인출할 수 있는
금액에 제한을 두는 패턴입니다.
이렇게 하는 이유는 특정 함수를 다수의 사용자가 무제한적으로 호출함으로 컨트랙트에 이상이 생기는 것을 방지하기 위함입니다.
contract SpeedBump {
struct Withdrawal {
uint amount;
uint requestedAt;
}
mapping (address => uint) private balances;
mapping (address => Withdrawal) private withdrawals;
uint constant WAIT_PERIOD = 7 days;
function deposit() public payable {
if(!(withdrawals[msg.sender].amount > 0)) {
balances[msg.sender] += msg.value;
}
}
function requestWithdrawal() public {
if (balances[msg.sender] > 0) {
uint amountToWithdraw = balances[msg.sender];
balances[msg.sender] = 0;
withdrawals[msg.sender] = Withdrawal({ amount: amountToWithdraw, requestedAt: now });
}
}
function withdraw() public {
if(withdrawals[msg.sender].amount > 0 && now > withdrawals[msg.sender].requestedAt + WAIT_PERIOD) {
uint amount = withdrawals[msg.sender].amount;
withdrawals[msg.sender].amount = 0;
msg.sender.transfer(amount);
}
}
}
deposit을 통해 입금한 Balances를 인출하기 위해서는 withdraw() 수행이 가능합니다
인출하기위해서는 두 가지 조건이 필요합니다
requestWithdrawal() 호출을 통해서 예약을 하고, WAIT_PERIOD의 인출시간이 지나야지만 최종적으로 인출이 가능합니다.
3. Rate Limit Pattern
- 위 패턴은 함수를 호출할 수 있는 빈도를 제한하는 패턴입니다.
아래의 코드는 함수 F가 한번 실행이 되면 1분이 지나야 만 다시 실행할 수 있도록 구현되어 있습니다.
contract RateLimit {
uint enabledAt = now;
modifier enabledEvery(uint t) {
if (now >= enabledAt) {
enabledAt = now + t;
_;
}
}
function f() public enabledEvery(1 minutes) {
// some code
}
}
4. Balance Limit Pattern
- 스마트 컨트랙트 내의 잔액의 최댓값을 설정하여, 최대값 이상으로 컨트랙트로 금액이 보내지는 것을 막는 패턴입니다.
contract LimitBalance {
uint256 public limit;
function LimitBalance(uint256 value) public {
limit = value;
}
modifier limitedPayable() {
require(this.balance <= limit);
_;
}
function deposit() public payable limitedPayable {
// some code
}
}
위 코드는 LimitBalance 함수를 통해 컨트랙트에서 보유할 수 있는 최대 잔액을 설정한 후, 보유한 잔액이 설정된 최대 잔액보다 작을 때만 deposit 함수를 실행할 수 있도록 구현되어 있습니다.
위와 같은 패턴들은 예기치 못하는 상황을 사전에 방지할 수 있으며 스마트 컨트랙트의 안정성을 높여주는 패턴이므로
꼭 염두에 두자
다음엔 Maintenance Pattern에 대해서 알아보자