Ryo Currency RYO
$0.0209 -1.86%
RYO如何解决类似Verge的离线时间戳记攻击
说不得大司

前言


不知道大伙还记得XVG当年被离线时间戳记攻击事件!!

今天我们就来看看RYO是怎么解决的呢!!


用Poisson概率检查阻止类似Verge的离线时间戳记攻击


51%的攻击不再只是理论上的可能性,而是开始成为小型硬币的实际关注点。尽管永远无法完全缓解它们,但最简单,最有利可图的攻击途径是使用伪造的时间戳以极快的速度打印数千个块的速率控制算法。为避免这种情况,大多数节点将不接受未来几分钟(又称为“未来时间限制”或FTL)超过几分钟的数据块。在本文中,我将解释如何绕过FTL以及如何减轻这种绕过。


如何绕过FTL检查


  1. 在本地节点上禁用FTL检查
  2. 断开与网络的所有连接。
  3. 将时间戳记提前X小时。
  4. 做任何需要欺骗速率控制算法的事情。对于Sumokoin算法,这是2-1模式的交替时间戳。
  5. 经过X个小时后,您可以使您的节点联机,并让其他节点重新组织您。


如何制止这种攻击


我们可以在步骤5上放置第二层保护。关键问题是,攻击者需要我们的节点来重组他。我们可以问一个问题:“假设速率控制算法没有失败,有人在5小时内提出10,000个块的可能性有多大?”

虽然您可能会大喊“这个假设是错误的!它确实失败了!”,但那些更倾向于科学的人会认识到,假设速率控制算法没有失败,这就是统计中的零假设。电脑不如您聪明,因此我们需要正式提出问题,并用他们能理解的东西(数字)来解决。


普鲁士军队来营救!


在19世纪末,统计学家开始整理各种数据,您猜对了脸书,我的意思是保险公司。一位非常聪明的人(Bortkiewicz)注意到,普鲁士骑兵军团的死亡情节与儿童自杀情节完全一样。这两个有什么共同点?正确的答案完全没有。

一个相当复杂的方程式稍后我们准备以固定的概率计算无关事件的概率。当然,这是我们找到区块的可能性。

这是什么意思?


这使我们可以说,有人诚实地在5小时内拿出10000块的机会很小,以致在宇宙的预期寿命中不会发生。这样,当我们看到它时,就意味着有人绕过了速率控制算法,我们可以拒绝该重组。


// MIT License
// Copyright (c) 2018 ryo-currency
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
struct common_config
{
static constexpr uint64_t POISSON_CHECK_TRIGGER = 10; // Reorg size that triggers poisson timestamp check
static constexpr uint64_t POISSON_CHECK_DEPTH = 60; // Main-chain depth of the poisson check. The attacker will have to tamper 50% of those blocks
static constexpr double POISSON_LOG_P_REJECT = -75.0; // Reject reorg if the probablity that the timestamps are genuine is below e^x, -75 = 10^-33
}
// Calculate ln(p) of Poisson distribution
// Original idea : https://stackoverflow.com/questions/30156803/implementing-poisson-distribution-in-c
// Using logarithms avoids dealing with very large (k!) and very small (p < 10^-44) numbers
// lam - lambda parameter - in our case, how many blocks, on average, you would expect to see in the interval
// k - k parameter - in our case, how many blocks we have actually seen
// !!! k must not be zero
// return - ln(p)
double calc_poisson_ln(double lam, uint64_t k)
{
double logx = -lam + k * log(lam);
do
{
logx -= log(k); // This can be tabulated
} while(--k > 0);
return logx;
}
//------------------------------------------------------------------
// This function attempts to switch to an alternate chain, returning
// boolean based on success therein.
bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::iterator> &alt_chain, bool discard_disconnected_chain)
{
[...]
// For longer reorgs, check if the timestamps are probable - if they aren't the diff algo has failed
// This check is meant to detect an offline bypass of timestamp < time() + ftl check
// It doesn't need to be very strict as it synergises with the median check
if(alt_chain.size() >= common_config::POISSON_CHECK_TRIGGER)
{
uint64_t alt_chain_size = alt_chain.size();
uint64_t high_timestamp = alt_chain.back()->second.bl.timestamp;
crypto::hash low_block = alt_chain.front()->second.bl.prev_id;
//Make sure that the high_timestamp is really highest
for(const blocks_ext_by_hash::iterator &it : alt_chain)
{
if(high_timestamp < it->second.bl.timestamp)
high_timestamp = it->second.bl.timestamp;
}
uint64_t block_ftl = check_hard_fork_feature(FORK_V3_DIFFICULTY) ? common_config::BLOCK_FUTURE_TIME_LIMIT_V3 : common_config::BLOCK_FUTURE_TIME_LIMIT_V2;
// This would fail later anyway
if(high_timestamp > get_adjusted_time() + block_ftl)
{
LOG_ERROR("Attempting to move to an alternate chain, but it failed FTL check! timestamp: " << high_timestamp << " limit: " << get_adjusted_time() + block_ftl);
return false;
}
LOG_PRINT_L1("Poisson check triggered by reorg size of " << alt_chain_size);
uint64_t failed_checks = 0, i = 1;
constexpr crypto::hash zero_hash = {{0}};
for(; i <= common_config::POISSON_CHECK_DEPTH; i++)
{
// This means we reached the genesis block
if(low_block == zero_hash)
break;
block_header bhd = m_db->get_block_header(low_block);
uint64_t low_timestamp = bhd.timestamp;
low_block = bhd.prev_id;
if(low_timestamp >= high_timestamp)
{
LOG_PRINT_L1("Skipping check at depth " << i << " due to tampered timestamp on main chain.");
failed_checks++;
continue;
}
double lam = double(high_timestamp - low_timestamp) / double(common_config::DIFFICULTY_TARGET);
if(calc_poisson_ln(lam, alt_chain_size + i) < common_config::POISSON_LOG_P_REJECT)
{
LOG_PRINT_L1("Poisson check at depth " << i << " failed! delta_t: " << (high_timestamp - low_timestamp) << " size: " << alt_chain_size + i);
failed_checks++;
}
}
i--; //Convert to number of checks
LOG_PRINT_L1("Poisson check result " << failed_checks << " fails out of " << i);
if(failed_checks > i / 2)
{
LOG_ERROR("Attempting to move to an alternate chain, but it failed Poisson check! " << failed_checks << " fails out of " << i << " alt_chain_size: " << alt_chain_size);
return false;
}
}
[...]
}


本文来自:https://github.com/ryo-currency/ryo-writeups/blob/master/poisson-writeup.md


~~~~~~~~~说不得大司~~~~~~~~~ 欢迎一起讨论技术,v号: ravencoin






2019年11月08日 12:28图文分享