{% raw %}
Symfony CSRF 教程
Symfony CSRF 教程展示了如何在 Symfony 应用中实现 CSRF 保护。
Symfony
Symfony 是一组可重用的 PHP 组件和一个用于 Web 项目的 PHP 框架。 Symfony 于 2005 年发布为免费软件。Symfony 的原始作者是 Fabien Potencier。 Symfony 的灵感来自 Djanog,Spring 和 ROR 框架。
CSRF
跨站点请求伪造(CSRF)是一种攻击,其中恶意用户试图使合法用户在不知情的情况下提交他们不打算提交的数据。 CSRF 攻击专门针对状态更改请求,而不是数据盗窃。 成功的 CSRF 攻击可以迫使用户执行状态更改请求,例如转移资金或更改其个人数据详细信息。
CSRF 保护的工作原理是在表单中添加一个隐藏字段,该字段包含仅应用和用户知道的值(令牌)。 这样可以确保用户(而非其他实体)正在提交给定的数据。
symfony/security-csrf
组件提供CsrfTokenManager
用于生成和验证 CSRF 令牌。 默认情况下,使用 Symfony 表单组件创建的表单包括 CSRF 令牌,Symfony 会自动检查它们,因此我们无需采取任何措施来防止 CSRF 攻击。 csrf_token()
Twig 函数为用户呈现 CSRF 令牌。
Symfony CSRF 保护示例
在下面的示例中,我们手动创建一个表单,为其实现 CSRF 保护。 在此应用中,我们在routes.yaml
文件中定义路由。
$ composer create-project symfony/skeleton csrf-app
$ cd csrf-app
使用composer
,我们创建一个新的 Symfony 框架项目并定位到项目目录。
$ composer require symfony/security-csrf
我们安装security-csrf
包。
$ composer require server --dev
我们安装开发 Web 服务器。
config/routes.yaml
index:
path: /
controller: App\Controller\AppController::index
process-form:
path: /process
controller: App\Controller\AppController::processForm
我们为应用定义了两个路由。 index
路由显示带有表单的主页。 process-form
处理提交的表单并检查 CSRF 令牌。
src/Controller/AppController.php
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class AppController extends AbstractController
{
public function index()
{
return $this->render('home/index.html.twig');
}
public function processForm(Request $request)
{
$token = $request->request->get("token");
if (!$this->isCsrfTokenValid('myform', $token))
{
return new Response('Operation not allowed', Response::HTTP_BAD_REQUEST,
['content-type' => 'text/plain']);
}
$name = $request->request->get("name");
$email = $request->request->get("email");
$msg = "$name with $email saved";
return new Response($msg, Response::HTTP_CREATED, ['content-type' => 'text/plain']);
}
}
AppController
具有两个动作:index()
和processForm()
。
public function index()
{
return $this->render('home/index.html.twig');
}
index()
函数呈现主页。 主页包含 HTML 表单。
$token = $request->request->get("token");
我们从请求中使用get()
方法检索 CSRF 令牌。
if (!$this->isCsrfTokenValid('myform', $token))
{
return new Response('Operation not allowed', Response::HTTP_BAD_REQUEST,
['content-type' => 'text/plain']);
}
我们使用isCsrfTokenValid()
方法检查令牌的有效性。 如果令牌无效,我们将返回带有Response::HTTP_BAD_REQUEST
代码的响应。 令牌myform
的名称在模板的 HTML 表单中指定。
templates/home/index.html.twig
{% extends 'base.html.twig' %}
{% block title %}Home page{% endblock %}
{% block body %}
<section class="ui container">
<form class="ui form" action="{{ path('process-form') }}" method="post">
<input type="hidden" name="token" value="{{ csrf_token('myform') }}" />
<div class="field">
<label>Name:</label>
<input name="name" type="text">
</div>
<div class="field">
<label>Email</label>
<input name="email" type="text">
</div>
<button class="ui button" type="submit">Send</button>
</form>
</section>
{% endblock %}
这是带有表单的主页的 Twig 模板。 表单使用语义 UI 库进行样式设置。
<form class="ui form" action="{{ path('process-form') }}" method="post">
表单动作指向process-form
路径。 表单的方法是 POST,这意味着必须进行 CSRF 保护。
<input type="hidden" name="token" value="{{ csrf_token('myform') }}" />
我们使用 CSRF 令牌添加隐藏的输入。 令牌是使用csrf_token()
生成的。
templates/base.html.twig
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>
{% block title %}Welcome!
{% endblock %}
</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css"
rel="stylesheet">
</head>
<body>
{% block body %}{% endblock %}
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.js"></script>
</html>
这是基本模板文件。 它加载语义 UI 库。
$ php bin/console server:run
我们运行该应用。
$ curl -d "name=Peter&email=peter@example.com" -X POST http://localhost:8000/process
Operation not allowed
如果我们尝试绕过表单并尝试使用curl
工具访问控制器操作,则会收到错误消息。
在本教程中,我们在 Symfony 应用中实现了 CSRF 保护。
您可能也对以下相关教程感兴趣: Symfony 验证教程, Symfony 表单教程, PHP 教程或列出所有 Symfony 教程。
{% endraw %}