Защита от атак Signature Replay
Несколько раз в задачах встречал уязвимости с подписями пользователей транзакций, что приводило к Front run и Signature Replay атакам. Мне захотелось чуть больше узнать о них. И для начала небольшой пример кода:
function unlock(
address _to,
uint256 _amount,
uint8[] _v,
bytes32[] _r,
bytes32[] _s
)
external
{
require(_v.length >= 5);
bytes32 hashData = keccak256(_to, _amount);
for (uint i = 0; i < _v.length; i++) {
address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
require(_isValidator(recAddr));
}
to.transfer(_amount);
}
Это сильно упрощенный код из аудиторского отчета одного из мостов. По своей сути, функция запрашивает как минимум 5 подписей, чтобы разблокировать сумму и отправить ее получателю.
Другими словами, поставщик должен собрать пять подписей на проведение транзакции, после чего он может отправить ее на исполнение. Поняли в чем подвох?
В тот момент, когда поставщик отправит транзакцию в мемпул, злоумышленник может скопировать данные подписи и сам вызвать unlock() уже со своим адресом для получения активов. И делать это можно до тех пор, пока пул не будет опустошен!
Самой простой защитой было бы добавить nonce в аргументы функции (индивидуальный номер) и проверку типа require(_nonce == nonce++).
Как же получше защититься от них?
Вот три самых популярных решения:
1. Сохранять message hash в контракте, и позже проверять его на предмет повтора;
2. Включать в message hash адрес контракта, чтобы удостовериться, что сообщение используется только в данном контрактом;
3. Никогда не генерировать message hash вместе с подписью пользователя.
Будьте очень осторожны в работе с подписями и в обязательном порядке проверяйте их уникальность.
#signaturereplay #signature #replay #security
Post #577
234
- 👍 2