这就是我需要做的就是用php和ajax来防止csrf攻击?

fxu*_*ser 4 php ajax csrf

我正在使用CodeigniterCSRF通过其config.php文件启用...

$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_token_name';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
Run Code Online (Sandbox Code Playgroud)

然后在我的ajax请求我得到了 cookie name

var cct = $.cookie('csrf_cookie_name');
Run Code Online (Sandbox Code Playgroud)

并在parameters:

csrf_token_name : cct
Run Code Online (Sandbox Code Playgroud)

我的问题:我还需要做其他事吗?

Vyk*_*tor 7

好的,CSRF的最常见情况(或最容易实现)是这样的:

<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=Fred" />
Run Code Online (Sandbox Code Playgroud)

因此,如果您假设您已登录,则bank.example.com您的cookie已"活着"并将随请求一起发送,因此请求将执行攻击者想要的操作,因此:

Cookie不会保护您免受CSRF的侵害

你能做什么:

尽可能多地发送请求POST(无需打扰用户),特别是编辑,创建和删除.隐藏安全性input type='hidden'比将URL 隐藏起来更容易.

检查引用者(是的,这个小东西阻止你几乎每次来自外部网站的CSRF攻击):

$url = parse_url( isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');
if( isset( $url['host']) && ($url['host'] == $_SERVER['SERVER_NAME'])){
   // Request have a go
}
Run Code Online (Sandbox Code Playgroud)

将临时安全令牌添加到这样的URL /article/delete/25/axdefm......

如果你花了一些时间生成漂亮的URL,你将被发送,因为这只会搞砸它们,这会带来一些问题,例如:

  • 当时的多个动作
  • 对新安全令牌的请求泛滥
  • 让令牌存活多久

您可以为安全令牌创建表,例如:

tokens (
  id INT,
  user_id INT,
  created DATETIME,
  expires DATETIME, -- One of those two should be enough
  value CHAR(30),
  PRIMARY (id),
  FOREIGN KEY (user_id) ...
);
Run Code Online (Sandbox Code Playgroud)

当某些操作需要授权令牌时,您将从数据库加载最后一个或创建新令牌,假设只有当所有可用的令牌都超过15分钟时才会创建新令牌:

function getToken( $userId, $eventIdentificator){
    // Hope this is self explanatory :)
    $db->deleteExpiredTokens();

    // Try to load token newer than 15 minutes
    $row = $db->fetchRow( 'SELECT value FROM tokens WHERE created >= ADD_INTERVAL( NOW(), -15 MINUTES) AND user_id = ?', array( $userId));

    // createToken will return `value` directly
    if( !$row){
        $row = createNewToken( $userId);
    } else {
        $row = $row['value'];
    }

    // Real token will be created as sha1( 'abacd' . 'delete_article_8');
    return sha1( $row . $eventIdentificator);
}

echo 'url?token=' . getToken( $userId, 'delete_article_' . $article['id']);
Run Code Online (Sandbox Code Playgroud)

这将如何行动:

  • 如果您在15分钟内请求相同操作的安全令牌,您将获得相同的令牌
  • 你将获得每个动作的唯一标记
  • 如果您将令牌到期时间设置为4小时,则令牌将在3:45至4:00之间激活
  • 如果攻击者试图在一分钟内向您发送200000个令牌请求,您在数据库中仍然只有一行
  • 每个用户一次最多可以在表中记录16条记录

如何检查令牌?

function checkToken( $userId, $eventIdentificator, $token){
    $db->deleteExpiredTokens();

    // Just find matching token with brute force
    $rs = $db->fetch_rowset( 'SELECT value FROM tokens WHERE created >= ADD_INTERVAL( NOW(), -15 MINUTES) AND user_id = ?', array( $userId));
    while( $row = $rs->fetch_row){
       if( $token == sha1( $row['value'] . $eventIdentificator)){
           return true;
       }
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

如果你不想确保动作不会发生两次(例如编辑文章,这适用于删除)只需添加revision_number或类似于你的东西$eventIdentificator).

尝试思考如果会发生什么:

  • 攻击者请求许多令牌
  • 用户将写几个小时的文章
  • 如果你有一个包含数百篇文章删除按钮的表格

我会使用上面提到的令牌系统,它感觉就像用户舒适/实现复杂性和安全性之间的平衡解决方案,期望与想法和注释的评论:)


Pbe*_*ben 5

防止跨站请求伪造 (CSRF) 攻击的最常见方法是将不可预测的质询令牌附加到每个请求并将它们与用户的会话相关联。

CodeIgniter 中的 CSRF 保护为你做,所以我认为没关系;-)