【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' => '爱好不能为空!'
        ]);
    }

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


相关推荐
wn5311 小时前
【Go - 类型断言】
服务器·开发语言·后端·golang
希冀1231 小时前
【操作系统】1.2操作系统的发展与分类
后端
GoppViper2 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
爱上语文3 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people3 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
罗政8 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
拾光师10 小时前
spring获取当前request
java·后端·spring
Java小白笔记11 小时前
关于使用Mybatis-Plus 自动填充功能失效问题
spring boot·后端·mybatis
JOJO___13 小时前
Spring IoC 配置类 总结
java·后端·spring·java-ee
白总Server14 小时前
MySQL在大数据场景应用
大数据·开发语言·数据库·后端·mysql·golang·php