# 表单构建
更改之前创建好的注册页面 `resources/views/user/auth/create.blade.php`:
~~~~ html
@extends('_layout.default')
@section('title', '注册')
@section('content')
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default mt-5">
<div class="panel-heading mb-3">
<h4>注册</h4>
</div>
<div class="panel-body">
<form method="POST"
action="{{ url('save') }}">
<input type="hidden" name="__token__" value="{{ $token }}" />
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">用户名</span>
</div>
<input type="text"
class="form-control"
name="name">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">邮箱</span>
</div>
<input type="email"
class="form-control"
name="email">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">密码</span>
</div>
<input type="password"
class="form-control"
name="password">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">确认密码</span>
</div>
<input type="password"
class="form-control"
name="password_confirm">
</div>
<button type="submit"
class="btn btn-primary btn-block">注册</button>
</form>
</div>
</div>
</div>
@stop
~~~~
修改控制器代码 `application/user/controller/Auth.php`:
~~~~ php
public function create()
{
$token = $this->request->token('__token__', 'sha1');
$this->assign('token', $token);
return $this->fetch();
}
~~~~
这一步的目的是将自定义 CSRF Token 传入模板当中.
## CSRF 防御
> 跨站请求伪造(英语:Cross-site request forgery),也被称为one-click attack 或者session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法. https://zh.wikipedia.org/zh/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0
> 假如一家银行用以运行转账操作的URL地址如下: `http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName`
那么,一个恶意攻击者可以在另一个网站上放置如下代码: `<img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">`
如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金.
这种恶意的网址可以有很多种形式,藏身于网页中的许多地方.此外,攻击者也不需要控制放置恶意网址的网站.例如他可以将这种地址藏在论坛,博客等任何用户生成内容的网站中.这意味着如果服务端没有合适的防御措施的话,用户即使访问熟悉的可信网站也有受攻击的危险.
## 防御措施
* 添加校验token
> 由于 `CSRF` 的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在 `cookie` 中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再运行 `CSRF` 攻击.这种数据通常是窗体中的一个数据项.服务器将其生成并附加在窗体中,其内容是一个伪随机数.当客户端通过窗体提交请求时,这个伪随机数也一并提交上去以供校验.正常的访问时,客户端浏览器能够正确得到并传回这个伪随机数,而通过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个伪随机数的值,服务端就会因为校验 `token` 的值为空或者错误,拒绝这个可疑请求.
* 检查 Referer 字段
> `HTTP` 头中有一个 `Referer` 字段,这个字段用以标明请求来源于哪个地址.在处理敏感数据请求时,通常来说,`Referer` 字段应和请求的地址位于同一域名下.以上文银行操作为例,`Referer` 字段地址通常应该是转账按钮所在的网页地址,应该也位于 `www.examplebank.com` 之下.而如果是 `CSRF` 攻击传来的请求,`Referer` 字段会是包含恶意网址的地址,不会位于 `www.examplebank.com` 之下,这时候服务器就能识别出恶意的访问.
这种办法简单易行,工作量低,仅需要在关键访问处增加一步校验.但这种办法也有其局限性,因其完全依赖浏览器发送正确的 `Referer` 字段.虽然 `http` 协议对此字段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,亦无法保证浏览器没有安全漏洞影响到此字段.并且也存在攻击者攻击某些浏览器,篡改其 `Referer` 字段的可能.
上面这段代码中的 `{:token()}` 是通过添加校验 `token` 来防止 `CSRF` 攻击.
- 第一章. 基础信息
- 1.1 序言
- 1.2 关于作者
- 1.3 本书源码
- 1.4 反馈纠错
- 1.5 安全指南
- 1.6 捐助作者
- 第二章. 开发环境布置
- 2.1 编辑器选用
- 2.2 命令行工具
- 2.3 开发环境搭建
- 2.4 浏览器选择
- 2.5 第一个应用
- 2.6 Git 工作流
- 第三章. 构建页面
- 3.1 章节说明
- 3.2 静态页面
- 3.3 Think 命令
- 3.4 小结
- 第四章. 优化页面
- 4.1 章节说明
- 4.2 样式美化
- 4.3 局部视图
- 4.4 路由链接
- 4.5 用户注册页面
- 4.6 集中视图
- 4.7 小结
- 第五章. 用户模型
- 5.1 章节说明
- 5.2 数据库迁移
- 5.3 查看数据表
- 5.4 模型文件
- 5.5 小结
- 第六章. 用户注册
- 6.1 章节说明
- 6.2 注册表单
- 6.3 用户数据验证
- 6.4 注册失败错误信息
- 6.5 注册成功
- 6.6 小结
- 第七章. 会话管理
- 7.1 章节说明
- 7.2 会话
- 7.3 用户登录
- 7.4 退出
- 7.5 小结
- 第八章. 用户 CRUD
- 8.1 章节说明
- 8.2 重构代码
- 8.3 更新用户
- 8.4 权限系统
- 8.5 列出所有用户
- 8.6 删除用户
- 8.7 访客模式
- 8.8 优化前端
- 8.9 小结
- 第九章. 微博 CRUD
- 9.1 章节说明
- 9.2 微博模型
- 9.3 显示微博
- 9.4 发布微博
- 9.5 微博数据流
- 9.6 删除微博
- 9.7 小结