【Laravel】Laravel中的表单安全

作者:Adlerian

表单是web常用的用户输入方式,也是安全漏洞的高发区。为了提高表单的安全性,laravel框架提供商防御CSRF攻击和自动验证功能。

1. 防御CSRF攻击

Laravel 框架为了提高安全性,默认开启了防御CSRF攻击。在表单以POST方式提交时,会自动验证是否含有CSRF令牌(Token),如果没有或者无效该请求就会被拦截。

1.1 什么是CSRF攻击

CSRF(Cross-Site Request Forgery,跨站请求伪造)是互联网中常见的一种攻击,它出现的原因是当用户在网站登录后,无法判断其接下来收到的请求是用户主动发起的,还是被其他的恶意程序伪造的。因此恶意程序可以伪造一个请求发给已登录的站点,造成用户在不知情的情况下执行相关操作。

CSRF攻击方式:分为GET方式和POST方式。

GET方式:

<img src="http://laravel.ltds/admin/data/delete/id/1">

<img>的src属性指向网站的后台,用来删除id为1的数据。

在已登录状态下浏览了包含这个<img>标签的页面时,就会执行删除数据操作。

POST方式:

html 复制代码
<form id="f" method="post" action="http://xxx/admin/data/delete" target="i">
  <input type="hidden" name="id" value="1">
</form>
<iframe style="display:none" name="i"></iframe>
<script>
  document.getElementById('f').submit();
</script>

以上代码隐藏了表单并且使得他可以直接自动执行提交表单,访问就会执行删除数据操作。

CSRF攻击之所以可以,是因为大部分网站在用户登录后,cookie保存了用户的SessionID,Cookie会在浏览器发送请求时自动携带,服务器无法分辨。

1.2 在Laravel防御CSRF攻击

(1)Laravel框架默认会对以POST方式发送过来的请求进行令牌验证,从而防御CSRF攻击。

(2)Laravel不会对以GET方式发送的请求进行令牌验证。在实际开发中,应对安全性要求高的操作(如添加、修改、删除数据)使用POST方式,而对安全性没有要求的操作(如查询)使用GET方式。

(3)POST方式的请求通常使用表单进行发送。在视图文件中编写表单时,可以通过模板语法"{{ csrf_field( ) }}"或"{{ csrf_token( ) }}"获取令牌,将令牌放入表单中,随表单一起提交,这样就可以通过CSRF 验证。

(4)如果表单缺少令牌或者令牌有误,则请求会被Laravel 拦截。

在路由文件web.php中添加get和post两种方式路由

php 复制代码
Route::get('text/index','TestController@form');
Route::post('text/transfer','TestController@transfer')->name('trans');

在控制器里面添加方法form,用来转到视图form

php 复制代码
   public function form()
    {
        return view('form');
    }

在视图文件夹新增视图页面resources\views\form.blade.php

php 复制代码
    <form action="{{route('trans')}}" method="post">
        收款人: <input type="text" name="name">
        转账金额: <input type="text" name="money">
        
        <input type="submit" value="转账">
    </form>

编写接收方法,我放在了transfer方法里面

php 复制代码
public function transfer()
    {
        return "转账成功";
    }

通过浏览器访问表单页面,被拦截

在from视图新增令牌

在视图中使用{{ csrf_field() }}{{ csrf_token() }}获取令牌。

{{ csrf_field() }} :获取一个隐藏域,自动填入令牌值。

{{ csrf_token() }} :获取令牌值,手动填入隐藏域中。

在开发中表单推荐使用field,在ajax交互中推荐使用token

php 复制代码
<form action="{{route('trans')}}" method="post">
       ......
		{{csrf_filed()}}
        <input type="submit" value="转账">
    </form>

重新提交,提交成功

1.3 在从CSRF验证中排除例外路由

在开发中,并不是所有的请求都需要防御CSRF攻击,为其他客户端(如微信小程序、手机应用等)提供后端接口时,则一般不需要CSRF 令牌验证,这是因为CSRF攻击主要是针对用户使用浏览器的情况。此时,可以从CSRF验证中排除例外路由。

app\Http\Middleware\VerifyCsrfToken.php 文件中可以添加要排除的路由,排除后就不会进行CSRF验证了。

所用路由排除使用*

2. 表单的自动验证

自动验证☞Laravel自动对用户提交的表单数据进行服务器端验证。表单一般有服务器端验证和客户端验证,laravel的自动验证是为了防止通过特殊手段绕过客户端验证。

2.1 验证规则

Laravel 提供了多种方法来验证用户输入的数据。默认情况下,Laravel 的控制器基类使用ValidatesRequests 类进行验证,该类提供了便捷的方法通过各种功能强大的验证规则来验证数据。

php 复制代码
 public function demo(Request $request)
 {
     $validatedData = $request->validate([
         //验证规则
         'title' => 'required|max:255',
         'body' => 'required',
     ]);
     // 验证通过,存储到数据库...
 }

常用的验证规则:

验证 - Laravel 5.8 - 面向 Web Artisans 的 PHP 框架

在框架中操作

(1) 定义路由

php 复制代码
Route::get('test/profile', 'TestController@profile');
Route::post('test/store', 'TestController@store')->name('store');

(2) 定义控制器

php 复制代码
public function profile(){
    return view('profile');
}
public function store(Request $request){
    $validatedData = $request->validate([
        'name' => 'required|string|bail|max:255',
        'email' => 'required|email',
        'age' => 'required|integer',
        'hobby' => 'required'
    ]);
}

(3) 创建视图

php 复制代码
<form action="{{ route('store') }}" method="post">
  姓名:<input type="text" name="name"><br>
  邮箱:<input type="text" name="email"><br>
  年龄:<input type="text" name="age"><br>
  爱好:<input type="checkbox" name="hobby">足球
        <input type="checkbox" name="hobby">篮球
        <input type="checkbox" name="hobby">排球<br>
  {{ csrf_field() }}
  <input type="submit" value="保存">
</form>

(4) 输出错误信息

用户输入的内容没有通过给定验证规则,Laravel会自动将用户重定向回上一个页面,并将所有验证错误信息自动保存到Session中。从Session中检查错误信息,并将检查到的错误信息自动绑定到视图,因此,可以通过$errors对象,用于在视图中输出错误信息。

php 复制代码
@if ($errors->any())
  <div class="alert alert-danger">
    <ul>
      @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
      @endforeach
    </ul>
  </div>
@endif

2.2 错误验证

Laravel 框架提供了多个方法用于显示页面的错误信息:

  • first()方法用于获取指定字段的第一条错误信息;

    php 复制代码
    @if ($errors->any())
        {{$errors->first('name')}}
    @endif
  • get()方法用于获取指定字段的所有错误信息;

    php 复制代码
    @if ($errors->any())
        @foreach ($errors->get('name') as $message) 
            {{ $message }}
        @endforeach
    @endif
  • has()方法用于判断错误信息中是否包含某个字段;

    php 复制代码
    @if ($errors->any())
        @if ($errors->has('name'))
            姓名格式错误!
        @endif
    @endif
  • all()方法用于获取所有字段的错误信息等。

    php 复制代码
    dump(session()->all());

2.3 自定义错误信息

在自动验证中,程序输出的错误信息默认是英文,我们可以通过自定义错误信息替代默认的提示信息。

如何自定义错误信息:

在控制器错误信息判断中调用validate()方法时,传入第2个参数来设置错误提示信息。

php 复制代码
 public function store(Request $request)
    {
        //用于接收表单提交内容
        //添加验证规则

        $validatedDate = $request->validate([
            'name' => 'required|string|bail|max:10',
            'email' => 'required|email',
            'age' => 'required|integer',
            'hobby' => 'required'
        ], [
            'name.required' => '姓名不能为空!',
            'name.string' => '姓名必须是字符格式!',
            'email.required' => '邮箱地址不能为空!',
            'email.email' => '邮件格式不正确',
            'age.required' => '年龄不能为空',
            'age.integer' => '年龄必须是数字',
            'hobby.required' => '爱好不能为空!'
        ]);
    }

访问表单,并提交错误表单


相关推荐
程序员清风8 小时前
贝壳一面:年轻代回收频率太高,如何定位?
java·后端·面试
考虑考虑8 小时前
Java实现字节转bcd编码
java·后端·java ee
AAA修煤气灶刘哥8 小时前
ES 聚合爽到飞起!从分桶到 Java 实操,再也不用翻烂文档
后端·elasticsearch·面试
爱读源码的大都督9 小时前
Java已死?别慌,看我如何用Java手写一个Qwen Code Agent,拯救Java
java·人工智能·后端
星辰大海的精灵9 小时前
SpringBoot与Quartz整合,实现订单自动取消功能
java·后端·算法
天天摸鱼的java工程师9 小时前
RestTemplate 如何优化连接池?—— 八年 Java 开发的踩坑与优化指南
java·后端
一乐小哥9 小时前
一口气同步10年豆瓣记录———豆瓣书影音同步 Notion分享 🚀
后端·python
LSTM979 小时前
如何使用C#实现Excel和CSV互转:基于Spire.XLS for .NET的专业指南
后端
三十_9 小时前
【NestJS】构建可复用的数据存储模块 - 动态模块
前端·后端·nestjs
武子康9 小时前
大数据-91 Spark广播变量:高效共享只读数据的最佳实践 RDD+Scala编程
大数据·后端·spark