2015-02-23 38 views
2

我正在寻找一种方法将CSRF令牌添加到我正在创建的应用程序中。需要注意的是,该应用程序目前不使用Cookie或会话。在PHP中没有Cookie的CSRF令牌

我很想找到一种方法来引入CSRF令牌,而无需:

  1. 在我的应用介绍状态。
  2. 使用会话cookie的或($_SESSION/$_COOKIE)存储

这是在所有的可能性,还是我停留在我的应用程序创建新的状态。

+0

如果没有服务器端存储的概念,令牌如何是好的? – 2015-02-23 17:12:51

+4

CSRF令牌*的种类是*状态验证。 “无状态CSRF令牌”是无意义的。 – 2015-02-23 17:13:28

+1

你提出的任何解决方案都不使用cookie或服务器端状态可能会挫败CSRF令牌的目的 – meagar 2015-02-23 17:14:56

回答

1

你可以,但它不会很安全。

下面是一个例子但不使用这一点,它可能是一个好主意

// Do this somewhere 
define('CSRF_SALT', '4dedMj4CWgBMNhRsoTpJlokwB5wTz7UsmF8Mq4uzFIbv'); 

$token = base64_encode(
    hash_hmac(
     'sha256', 
     date('Ymd') . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'], 
     CSRF_SALT, 
     true 
    ) 
); 

if (\hash_equals($_POST['security_token'], $token)) { 
    // Form passes validation 
} 

的缺点是,这些标记是固有可重复使用的,因此,如果一个泄漏,攻击者可以简单地重复使用(或重新计算)它。您也可以尝试在散列计算中添加表单action =“”的值。

function getToken($action) 
{ 
    return base64_encode(
     hash_hmac(
      'sha256', 
      hash_hmac(
       'sha256', 
       date('Ymd') . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'], 
       hash('sha256', $action, true), 
       true 
      ), 
      CSRF_SALT, 
      true 
     ) 
    ); 
} 

echo "<form action='register.php' method='post'>\n"; 
echo "<input type='hidden' name='security_token' value='".getToken('register.php')."' />\n"; 
// ... 

无论如何,你对会话有什么诅咒?

+0

我不喜欢会话的原因是因为它需要服务器端存储。我工作在一个开源库,这意味着有更多的东西需要记录,理想情况下,我还需要提供一种方法使其在多个负载平衡的服务器上工作。 – Evert 2015-02-27 18:07:16

+0

我认识到memcache支持的会话存储可以帮助解决这个问题......但我必须解释的越少越好。很好的答案,但最终我决定只使用一个cookie(但没有会话)。 – Evert 2015-02-27 18:07:57

+0

https://resonantcore.net/blog/2015/02/modern-defense-against-csrf-attacks - 如果你使用composer,你可以使用resonancecore/anti-csrf作为依赖。 – 2015-02-28 05:17:26

-1

CSRF保护通过比较嵌入在页面中的令牌和与页面发送到的浏览器相关的令牌来起作用。

在没有引入状态的情况下做到这一点是绝对不可能的。

+0

答案听起来非常自信(“绝对不可能”),并且“绝对”错误。我不希望它似乎是一个对我不了解这个领域的人可能是正确的答案。 – Iiridayn 2017-08-17 23:19:51

+0

以上是对@Evert现在删除的评论的回应,他曾想知道为什么此问题之前已被低估。 – Iiridayn 2017-09-13 23:13:32

0

您可以使用轻量级数据库并存储令牌以及ip地址,用户代理,到期时间和请求的url,或者您可以尝试使用数据库和会话存储来存储创建令牌的密钥。例如。

$post = array(); 
If (isset($_POST) && !empty($_POST)) { 
    If (isset($_POST['csrftoken']) && isset($_SESSION['csrfkey'])) { 
     // check if csrftoken exists in db and fetch the row 
     $hash = hash('sha256', $row['String'] . $_SESSION['csrfKey']); 
     // delete the db record 
     If ($hash === $_POST['csrfToken']) { 
      $post = (array) $_POST; 
      // check if expiry time has not passed 
      // check requested url 
      // check user agent and ip adres 
     } 
    } 
    $_REQUEST = null; 
    $_POST = null; 
} 

If (!isset($_SESSION['csrfKey'])) { 
    $_SESSION['csrfKey'] = uniqid('key_', true); 
} 
$string = uniqid('token_', true); 
$token = hash('sha256', $string . $_SESSION['csrfKey']); 
// save token and string along with expirytime in db 
echo "<input type='hidden' name='csrftoken' value='" . $token . "' />"; 
-1

嵌入像一个轻量级JWT到窗体,并检查它在服务器上,提供为准断言你要检查 - 通常你会添加当前时间标记,这样就可以到期令牌。

的基本程序是:

  • 需要一些数据,你想约断言令牌 - 通常是一个时间戳,如果有一个用户,一般的东西,唯一标识用户(自然人或代理键)。
  • 序列化此数据 - 即JSON
  • HMAC用密钥只有服务器知道
  • 序列化的数据和HMAC
  • 一起发送串行数据。当你得到的令牌(串行数据+ HMAC)返回,如果HMAC丢失或无效,则拒绝。如果是时间戳,请检查当前时间是否过远。
  • 验证你想要的任何东西,然后相信这是你自己的令牌 - 不必将其存储在数据库中。