phpgt/csrf

自动防护跨站请求伪造。

维护者

详细信息

github.com/PhpGt/Csrf

源代码

问题

资助包维护!
PhpGt

v1.9.0 2022-09-23 12:03 UTC

README

这个库自动为您处理CSRF保护,包括生成令牌、将其注入页面中的所有表单,并在收到POST请求时验证是否存在有效的令牌。

Build status Code quality Code coverage Current version PHP.Gt/Csrf documentation

用法:三步保护

CSRF库做两件事

  • 将CSRF令牌注入form
  • 验证POST请求以确保它们包含一个有效的令牌

每件事都是一个单独的方法调用,但您需要先进行设置。

步骤1:设置

首先创建TokenStore。目前有两种实现方式——ArrayTokenStoreSessionTokenStore。《ArrayTokenStore》是最基本的,不会以任何方式持久化,但可以扩展到自定义集成。《SessionTokenStore》是一个内置实现,可以在请求之间持久化令牌,以便一个页面请求生成的令牌可以在另一个请求中检查。添加CSRF保护的最简单方法是使用Session。

use Gt\Csrf\SessionTokenStore;

// $session is an object-oriented representation of $_SESSION
// that implements the Gt\Session\SessionContainer Interface.
$tokenStore = new SessionTokenStore($session);

步骤2:验证

在运行任何其他代码(特别是可能影响数据的代码)之前,如果需要,您应该检查是否存在有效的CSRF令牌。

use Gt\Csrf\Exception\CSRFException;

if(this_is_a_post_request()) {
	try {
		$tokenStore->verify();
	}
	catch(CSRFException $e) {
// Stop processing this request and get out of there!
	}
}

如果请求包含POST但没有有效的CSRF令牌,将会抛出CSRFException——因此您应该计划捕获它。记住,如果发生这种情况,请求是欺诈性的,所以您不应该处理它!

步骤3:为下一次注入

最后,一旦您处理完HTML代码并且它准备好发送回客户端,您应该注入CSRF令牌。如果您不这样做,当页面提交时,请求将无法通过步骤2!

use Gt\Csrf\HTMLDocumentProtector;

// The html can come in as anything accepted by Gt\Dom\HTMLDocument - here it's a
// plain string in a variable.
$html = "<html>...</html>";

// Now do the processing.
$protector = new HTMLDocumentProtector($html, $tokenStore);
$protector->protect();

// Output the HTML of the document - you will see the new fields have
// been automatically injected.
echo $protector->getHTMLDocument();

使用不同长度的令牌

默认情况下,生成32个字符的令牌。它们使用集合[a-zA-Z0-9]中的字符,这意味着64位令牌,一个每秒发送10万个请求的蛮力攻击者需要约2.93亿年才能猜测。如果这看起来既过多又不足,您可以使用TokenStore::setTokenLength()更改令牌长度。

关于客户端请求的特殊说明

请注意,如果您的页面上有多个表单,将为每个表单生成并注入一个唯一的令牌。当使用客户端请求(XMLHTTPRequest或Fetch,也称为AJAX)提交表单时,响应将包含一个新令牌,该令牌必须在页面上刷新以供下一次提交使用。

如果您希望每个页面只有一个令牌,并且该令牌可以跨所有表单共享,这可以通过将TOKEN_PER_PAGE参数传递给projectAndInject方法来配置:$page->protectAndInject(HTMLDocumentProtector::TOKEN_PER_PAGE);

每页存储一个令牌将减少所需的服务器资源,但并发客户端请求将失败,这就是为什么默认情况下每个表单使用一个令牌的原因。

存储在会话中令牌的替代方案

该包包括一个ArrayTokenStore,它可以在会话中存储。您可以通过扩展TokenStore并实现抽象方法来实施替代令牌存储,例如RDBMS或NoSQL。