phpgt/Csrf

GitHub: phpgt/Csrf

为 PHP Web 应用提供全自动的 CSRF 令牌生成、表单注入与请求验证,让开发者用最少的代码抵御跨站请求伪造攻击。

Stars: 7 | Forks: 7

# 自动防御跨站请求伪造。 本库会自动为您处理 [CSRF 防御](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)),包括生成令牌、将其注入页面中的所有表单,然后在每次接收到 POST 请求时验证是否存在有效令牌。 Build status Code quality Code coverage Current version PHP.GT/Csrf documentation ## 用法:三步实现防御 CSRF 库主要做两件事: * 将 CSRF 令牌注入到 `form` 中 * 验证 `POST` 请求以确保其包含有效令牌 每项操作仅需一次方法调用,但您需要先进行设置。 ### 第一步:设置 首先创建 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); ``` ### 第二步:验证 在运行任何其他代码(尤其是可能影响数据的操作)之前,您应该检查在需要时是否已存在有效的 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` —— 因此您应该做好捕获它的准备。请记住,如果发生这种情况,说明该请求是伪造的,因此您不应处理它! ### 第三步:为下次提交注入令牌 最后,一旦您处理完 HTML 代码并准备将其发送回客户端,您应该注入 CSRF 令牌。如果不这样做,当页面提交时,将无法通过第二步的验证! ``` 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 = "..."; // 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 位的令牌,暴力破解攻击者以每秒 100,000 次请求的速度大约需要 293 万年才能猜中。如果您觉得这个长度过长或不足,可以使用 `TokenStore::setTokenLength()` 更改令牌长度。 ## 关于客户端请求的特别说明 请注意,如果您的页面上有多个表单,系统将为每个表单生成并注入一个唯一的令牌。当使用客户端请求(XMLHTTPRequest 或 Fetch,又称 AJAX)提交表单时,响应将包含一个新的令牌,必须在页面中刷新该令牌以备下次提交使用。 如果您希望每个页面只有一个令牌,并在所有表单之间共享,可以通过将 TOKEN_PER_PAGE 参数传递给 projectAndInject 方法来进行配置:`$page->protectAndInject(HTMLDocumentProtector::TOKEN_PER_PAGE);`。 每个页面存储一个令牌将减少所需的服务器资源量,但并发的客户端请求将会失败,这就是为什么默认采用每个表单一个令牌的原因。 ## Session 之外的其他令牌存储方案 本包包含了 `ArrayTokenStore`,可以存储在 Session 中。您可以通过继承 `TokenStore` 并实现其抽象方法,来构建如 RDBMS 或 NoSQL 等其他备选的令牌存储方式。 # 骄傲地获得赞助 [JetBrains 开源赞助计划](https://www.jetbrains.com/community/opensource/) [![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://www.jetbrains.com/community/opensource/)
标签:CISA项目, CSRF防护, OpenVAS, PHP, Session, Syscall, Token验证, Web安全, Web开发, YAML, 中间件, 会话管理, 多模态安全, 安全库, 开源库, 搜索引擎爬虫, 网络安全, 蓝队分析, 表单保护, 跨站请求伪造, 防御机制, 隐私保护