Symfony CSRF 教程

Symfony CSRF 教程展示了如何在 Symfony 应用中实现 CSRF 保护。

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(Requestrequest)
    {
        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 验证教程Symfony 表单教程PHP 教程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程