phpgt / csrf
自动防护跨站请求伪造。
Requires
- php: >=8.1
- phpgt/dom: ^v4.0
- phpgt/session: ^v1.1
Requires (Dev)
- phpstan/phpstan: ^v1.8
- phpunit/phpunit: ^v9.5
This package is auto-updated.
Last update: 2024-09-09 20:08:05 UTC
README
这个库自动为您处理CSRF保护,包括生成令牌、将其注入页面中的所有表单,并在收到POST请求时验证是否存在有效的令牌。
用法:三步保护
CSRF库做两件事
- 将CSRF令牌注入
form
- 验证
POST
请求以确保它们包含一个有效的令牌
每件事都是一个单独的方法调用,但您需要先进行设置。
步骤1:设置
首先创建TokenStore。目前有两种实现方式——ArrayTokenStore
和SessionTokenStore
。《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。