php 网站中防止重放攻击的好方法

a good approach to prevent replay attack in websites with php

我是网络开发的菜鸟。我正在设计一个 MVC 登录页面,为了防止重放攻击,每当用户请求登录页面时,我都会创建一个会话。我的代码如下:

public function login(){
  if($_SERVER['REQUEST_METHOD'] == 'GET') {
  session_start();
  $_SESSION["requestToken"] = generateToken(3);

}else if ($_SERVER['REQUEST_METHOD'] == 'POST'){
  session_start();
  if (isset($_SESSION["requestToken"])){
     if(successfulLogin()){
     unset($_SESSION["requestToken"]);
     session_destroy();
    }
}else{

    header("location:localhost:public/users/login");
}
}

我读过一篇文章,其中实施了类似的方法来防止重播攻击,但我引用它说,“这远非一个完整的解决方案。它有缺陷和悬而未决的问题”。 Here

你能帮我找出我的方法的问题并告诉我哪种方法最适合应用吗?

我来晚了,但我希望我的回答能帮助其他一些试图保护他们的网页/API免受重放攻击的人。我使用以下方法来保护我的 API 免受重放攻击

应用端

  1. 首次使用您的应用程序时,或者如果您的应用程序需要登录,则在服务器上为设备生成一个唯一的 device_id/token,然后您可以在登录时生成令牌
  2. 每当应用程序调用服务器时,它都会在 HTTP headers 中添加以下内容
    • 令牌
    • 128 个字符长的随机值 (Random1)
    • 设备的当前 Unix 时间戳
    • “令牌+|||+随机1+|||+时间戳”(随机2)的SHA256

服务器端

当 API 收到呼叫时,它会像这样验证 headers

  • 检查令牌是否是数据库中存在的有效令牌(您可以 实施过期机制以使其更安全) -

  • 检查时间戳是否有效

  • 生成“Token+|||+Random1+|||+Timestamp”的SHA256并进行比较 header.

    的 Random2
  • 检查您的数据库中是否不存在此 SHA256 结果

  • 如果所有检查都通过,则根据此令牌将此 SHA256 结果保存在数据库中。

您可以通过添加更多随机数来提高安全性。在我的示例中,您可以看到我对 3 个管道进行了两次硬编码。您可以使管道数量随机。

示例服务器端PHP代码

//This function will perform all the steps to validate the request
//returns TRUE if all good else FALSE
function headers_valid(){
    $headers=getallheaders();
    if (!isset($headers["Token"])
        || !isset($headers["Random1"]) 
        || !isset($headers["Timestamp"]
        || !isset($headers["Random2"])
        ){
            return FALSE;
        }
    
    $token=$headers["Token"];
    $random1=$headers["Random1"];
    $timestamp=$headers["Timestamp"];
    $random2=$headers["Random2"];

    if (!is_numeric($timestamp)){
        return FALSE;
    }

    $ts=intval($timestamp);
    $tsNow=time();
    $diffTs=$tsNow-$ts;
    if ($diffTs<0){
        $diffTs*=-1;
    }
    //extra check to make sure that timestamp is not off 
    //by 1 or more minutes
    if ($diffTs>=60){
        return FALSE;
    }

    $hashInput=$token."|||".$random1."|||".$timestamp;
    $calcHash=strtolower(hash("sha256",$hashInput));
    if (strtolower($random2)!=$calcHash){
        return FALSE;
    }
    //add your database code. following is a dummy database code
    $row=resultof("SELECT hash FROM request_hash WHERE hash='".$calcHash."'");
    //if row is returned by this query then return false
    if (row_exists($row))
        return FALSE;
    //all good now you can store this hash in your database
    execute_query("INSERT INTO request_hash(hash) VALUES('".$calcHash."')");
    return TRUE;
}

我希望我的回答能帮助其他想要防范重放攻击的人