HTTP路由实例教程(三)—— CSRF攻击原理及其防护

1、什么是CSRF攻击 CSRF是跨站请求伪造(Cross-site request forgery)的英文缩写。关于CSRF攻击原理及其防护,可查看Github上的这个项目:理解CSRF,说得比较详细和透彻。 2、Laravel中如何避免CSRF攻击 Laravel框架中避免CSRF攻击很简单:Laravel自动为每个用户Session生成了一个CSRF Token,该Token可用于验证登录用户和发起请求者是否是同一人,如果不是则请求失败。 Laravel提供了一个全局帮助函数csrf_token来获取该Token值,因此只需在视提交图表单中添加如下HTML代码即可在请求中带上Token:

该段代码等同于全局帮助函数csrf_field的输出:

在Blade模板引擎中还可以使用如下方式调用:

测试代码 我们在routes.php中定义如下代码:

在浏览器中我们输入http://laravel.app:8000/testCsrf,点击“Test”按钮,浏览器输出:

则表示请求成功,否则,如果我们定义GET路由如下:

则点击“Test”按钮,则抛出TokenMismatchException异常。 3、从CSRF验证中排除指定URL 并不是所有请求都需要避免CSRF攻击,比如去第三方API获取数据的请求。 可以通过在VerifyCsrfToken(app/Http/Middleware/VerifyCsrfToken.php)中间件中将要排除的请求URL添加到$except属性数组中:

这样我们刷新页面,再次在http://laravel.app:8000/testCsrf页面中点击“Test”按钮,则页面不会报错,正常输出如下内容:

4、X-CSRF-Token及其使用 如果使用Ajax提交POST表单,又该如何处理呢?我们可以将Token设置在meta中:

然后在全局Ajax中使用这种方式设置X-CSRF-Token请求头并提交:

Laravel的VerifyCsrfToken中间件会检查X-CSRF-TOKEN请求头,如果该值和Session中CSRF值相等则验证通过,否则不通过。 5、X-XSRF-Token及其使用 除此之外,Laravel还会将CSRF的值保存到名为XSRF-TOKEN的Cookie中,然后在VerifyCsrfToken中间件验证该值,当然,我们不需要手动做任何操作,一些JavaScript框架如Angular会自动帮我们实现。 6、Laravel中CSRF验证原理分析 说了这么多使用方式,接下来我们来分析下源码,看看Laravel底层到底是如何避免CSRF攻击的: 1)首先Laravel开启Session时会生成一个token值并存放在Session中(Illuminate\Session\Store.php第90行start方法),对应源码如下:

2)然后重点分析VerifyToken中间件的handle方法,该方法中先通过isReading方法判断请求方式,如果请求方法是HEAD、GET、OPTIONS其中一种,则不做CSRF验证; 3)再通过shouldPassThrough方法判断请求路由是否在$excpet属性数组中进行了排除,如果做了排除也不做验证; 4)最后通过tokensMatch方法判断请求参数中的CSRF TOKEN值和Session中的Token值是否相等,如果相等则通过验证,否则抛出TokenMismatchException异常。 对应源码如下:

注:tokensMatch方法首先从Request中获取_token参数值,如果请求中不包含该参数则获取X-CSRF-TOKEN请求头的值,如果该请求头也不存在则获取X-XSRF-TOKEN请求头的值,需要注意的是X-XSRF-TOKEN请求头的值需要调用Encrypter的decrypt方法进行解密。   from:http://laravelacademy.org/post/525.html

龙生   15 Aug 2017
View Details

HTTP路由实例教程(二)—— 路由命名和路由分组

1、路由命名——给路由起个名字 1.1 基本使用 我们使用as关键字来为路由命名:

路由命名可以让我们在使用route函数生成指向该路由的URL或者生成跳转到该路由的重定向链接时更加方便:

我们在浏览器中访问http://laravel.app:8000/testNamedRoute时输出http://laravel.app:8000/hello/laravelacademy,然后我们修改上述闭包内代码:

再次在浏览器中访问http://laravel.app:8000/testNamedRoute时会跳转到http://laravel.app:8000/hello/laravelacademy。 我们甚至还可以在使用带参数的路由命名:

对应的测试路由定义如下:

这样,当我们在浏览器中访问http://laravel.app:8000/testNamedRoute时会跳转到http://laravel.app:8000/hello/laravelacademy/1 1.2 路由分组时路由命名方式 再来看一个更复杂的例子,使用路由分组时如何定义路由命名?官网文档提供的例子如下:

在Route门面的group方法中使用一个as关键字来指定该路由群组中所有路由的公共前缀,然后再在里面每个路由中使用as关键字为该路由命名。 这样我们可以通过如下方式来生成该路由URL:

2、路由分组 路由分组就是将一组拥有相同属性(中间件、命名空间、子域名、路由前缀等)的路由使用Route门面的group方法聚合起来。 2.1 中间件 首先我们在应用根目录下运行如下Artisan命令生成一个测试用的中间件TestMiddleware:

这样会在/app/Http/Middleware目录下生成一个TestMiddleware.php文件,打开该文件编辑TestMiddleware类的handle方法如下:

我们在中间件中定义这段业务逻辑的目的是年龄18岁以下的未成年人不能访问。 然后我们打开/app/Http/Kernal.php文件,新增TestMiddleware到Kernel的$routeMiddleware属性:

接下来我们在routes.php中定义路由如下:

这样当我们在浏览器中访问http://laravel.app:8000/write/laravelacademy?age=15或者http://laravel.app:8000/update/laravelacademy?age=15时就会跳转到http://laravel.app:8000/age/refuse,并显示:

2.2 命名空间 默认情况下,routes.php中的定义的控制器位于App\Http\Controllers命名空间下,所以如果要指定命名空间,只需指定App\Http\Controllers之后的部分即可:

2.3 子域名 子域名可以通过domain关键字来设置:

这样我们在浏览器中访问http://write.laravel.app:8000/write/laravelacademy,则输出

访问http://update.laravel.app:8000/write/laravelacademy时,则输出:

注意:要想让子域名解析生效,需要在hosts中绑定IP地址 2.4 路由前缀 如果路由群组中的所有路由包含统一前缀,则我们可以通过在group方法中设置prefix属性来指定该前缀:

这样我们就可以通过http://laravel.app:8000/laravelacademy/write或者http://laravel.app:8000/laravelacademy/update来访问对应的操作。 我们甚至还可以在路由前缀中指定参数:

这样我们在浏览器中访问http://laravel.app:8000/laravelacademy/5.1/write,则对应会输出:

龙生   15 Aug 2017
View Details

HTTP路由实例教程(一)—— 基本使用及路由参数

1、路由基本使用示例 1.1 默认示例 Laravel中所有路由定义在/app/Http/routes.php文件中,该文件默认定义了应用的首页路由:

这段代码的意思是:当访问应用首页http://laravel.app:8000(使用Homestead虚拟机作为开发环境)的时候,返回/resources/views/welcome.blade.php视图中的内容并渲染到浏览器页面中: 以上是应用自带的路由示例,下面我们来自定义一些示例来演示路由的基本使用。 1.2 GET请求路由定义 对页面常见的请求方式有GET和POST,上面这个例子就是使用GET路由的例子,接下里来我们自定义一个/hello请求:

我们在浏览器中输入http://laravel.app:8000/hello,以上代码在浏览器中输出:

1.3 POST请求路由示例 然后我们来演示一个POST请求的例子:

首先我们定义一个/testPost页面用于提交POST请求表单,在http://laravel.app:8000/testPost页面点击“Test”按钮,页面跳转到http://laravel.app:8000/hello并显示:

表明这是通过POST请求访问而非GET请求。 1.4 其它便捷路由定义 还可以使用Route门面上的match方法匹配多种请求方式:

当然还使用更方便的any方法匹配所有请求方式:

效果都一样。 2、路由参数使用示例 2.1 必选参数

在浏览器中访问http://laravel.app:8000/hello/Laravel输出:

当然还可以指定多个参数:

这样在浏览器中访问http://laravel.app:8000/hello/Laravel/by/Laravel学院则会输出:

注意以上参数是必选的,如果没有输入参数会抛出MethodNotAllowedHttpException或NotFoundHttpException异常。 此外闭包函数中的参数与路由参数一一对应。 2.2 可选参数 有时候我们并不总是想要输入对应参数,也就是说,我们期望参数是可有可无的,我们通过这种方式来定义:

我们同时为可选参数指定了默认值,这样当我们访问http://laravel.app:8000/hello时输出:

当我们访问http://laravel.app:8000/hello/Laravel学院的时候输出:

2.3 正则约束 有时候我们希望对路由有更加灵活的条件约束,可以通过正则表达式来实现:

该条件约束意味着$name参数只能包含大小写字母,如果包含数字或中文就会抛出NotFoundHttpException异常。 如果我们想要在全局范围内对参数进行条件约束,可以在RouteServiceProvider的boot方法中做如下定义:

我们访问http://laravel.app:8000/hello/Laravel123/by/Laravel学院时一样会抛出NotFoundHttpException异常。这意味着boot方法定义的参数条件约束将会应用到所有包含该参数的路由中。 此外,服务提供者的boot方法在所有服务提供者的register方法执行完毕后开始执行,也就是说,我们可以在boot方法对任意服务容器中的对象进行依赖注入。   from:http://laravelacademy.org/post/398.html

龙生   15 Aug 2017
View Details

upgrade Laravel 5.2 to 5.3

昨天折腾了1个小时,把5.2升级到5.3,目前是成功了,遇见了几个小坑。但是之后的坑不可预见,分享一下遇见的小坑。 前提是必须仔细阅读的官方文档。 刚开始的时候,改了composer文件,直接更新,出现了错误 Declaration of App\Providers\EventServiceProvider::boot() should be compatible with Illuminate\Foundation\Support\Providers\EventServiceProvider::boot(Illuminate\Contracts\Events\Dispatcher $events) 然后我去看了下官方文档,具体忘记在哪里了,主要是bootstrap里面的cache文件没有清理,所以必须得先清理,运行下面的命令 php artisan route:cache php artisan view:clear php artisan config:clear php artisan cache:clear php artisan clear-compiled php artisan optimize php artisan route:cache 更新完之后会报错, ErrorException in EventServiceProvider.php line 8: 按照官方文档解释,就是这些功能已经改变,不需要参数,所以,我们找到相应的位置,把参数去掉即可 public function boot() { parent::boot(); }   from:https://laravel-china.org/topics/3767/upgrade-laravel-52-to-53

龙生   14 Aug 2017
View Details

Caddy,一个用Go实现的Web Server

这是一个Web Server的时代,apache2与nginx共舞,在追求极致性能的路上,没有最高,只有更高。但这又是一个追求个性化的时代,有些Web Server并没有去挤“Performance提升”这一独木桥,而是有着自己的定位,Caddy就是这样一个开源Web Server。 Caddy的作者Matt Holt在caddy官网以及FAQ中对caddy的目标阐释如下: 其他Web Server为Web而设计,Caddy为human设计。功能定位上,与经常充当最前端反向代理的nginx不同,caddy致力于成为一个易用的静态 文件Web Server。可以看出Caddy主打易用性,使用配置简单。并且得益于Go的跨平台特性,caddy很容易的支持了三大主流平台:Windows、 Linux、Mac。在Caddy开发者文档中,我们可以看到caddy还可以在Android(linux arm)上运行。caddy目前版本为0.7.1,还不稳定,且后续版本可能变化较大,甚至与前期版本不兼容,因此作者目前不推荐caddy在生产环境被 重度使用。 关注caddy,是因为caddy填补了go在通用web server这块的空白(也许有其他,但我还不知道),同时Web server in go也“响应”了近期Golang去C化的趋势(Go 1.5中C is gone!),即便caddy作者提到caddy的目标并非如nginx那样。但未来谁知道呢?一旦Go性能足够高时,一旦caddy足够稳定时,自然而 然的就会有人将其用在某些应用的生产环境中替代nginx或apache2了。一套全Go的系统,在部署、运维方面也是有优势的。 一、安装和运行caddy 和诸多go应用一样,我们可以直接从caddy的github.com releases页中找到最新发布版(目前是0.7.1)的二进制包。这里使用的是caddy_darwin_amd64.zip。 下载解压后,进入目录,直接执行./caddy即可将caddy运行起来。 $caddy 0.0.0.0:2015 在浏览器里访问localhost:2015,页面上没有预期显示的类似"caddy works!”之类的默认Welcome页面,而是“404 Not Found"。虽然这说明caddy已经work了,但没有一个default welcome page毕竟对于caddy beginer来说并不友好。这里已经向作者提了一个sugguestion issue。 二、caddy原理 Go的net/http标准库已经提供了http server的实现,大多数场合这个http server都能满足你的需要,无论是功能还是性能。Caddy实质上也是一个Go web app,它也import net/http,嵌入*http.Server,并通过handler的ServeHTTP方法为每个请求提供服务。caddy使用 http.FileServer作为处理 静态文件的基础。caddy的诱人之处在于其middleware,将诸多middleware串成一个middleware chain以提供了灵活的web服务。另外caddy中的middleware还可以独立于caddy之外使用。 caddy从当前目录的Caddyfile(默认)文件中读取配置,当然你也可以通过-conf指定配置文件路径。Caddyfile的配置格式 的确非常easy,这也符合caddy的目标。 Caddyfile总是以站点的Addr开始的。 单一站点的Caddyfile样例如下: //Caddyfile localhost:2015 gzip log ./2015.log Caddy也支持配置多个站点,类似virtualhost的 配置(80端口多路复用): //Caddyfile foo.com:80 { log ./foo.log gzip } bar.com:80 { log ./bar.log gzip } 为了实现风格上的统一,单一站点也最好配置为如下这种格式(代码内部称之为    Server Block): localhost:2015 { gzip log ./2015.log } 这样Caddyfile的配置文件模板样式类似于下面这样: host1:port { middleware1 middleware2 { … … } […]

龙生   14 Aug 2017
View Details

Neo4j

Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中——但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。 Neo4j因其嵌入式、高性能、轻量级等优势,越来越受到关注.

龙生   14 Aug 2017
View Details

beanstalkd

Beanstalk,一个高性能、轻量级的分布式内存队列系统,最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web应用系统的页面访问延迟,支持过有9.5 million用户的Facebook Causes应用。 后来开源,现在有PostRank大规模部署和使用,每天处理百万级任务。Beanstalkd是典型的类Memcached设计,协议和使用方式都是同样的风格,所以使用过memcached的用户会觉得Beanstalkd似曾相识。

龙生   14 Aug 2017
View Details

markdown

Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。 Markdown具有一系列衍生版本,用于扩展Markdown的功能(如表格、脚注、内嵌HTML等等),这些功能原初的Markdown尚不具备,它们能让Markdown转换成更多的格式,例如LaTeX,Docbook。Markdown增强版中比较有名的有Markdown Extra、MultiMarkdown、 Maruku等。这些衍生版本要么基于工具,如Pandoc;要么基于网站,如GitHub和Wikipedia,在语法上基本兼容,但在一些语法和渲染效果上有改动。

龙生   13 Aug 2017
View Details

现代 PHP 新特性系列(七) —— 内置的 HTTP 服务器

从 PHP 5.4.0 起,PHP内置了Web服务器,这对于认为需要Apache或Nginx才能预览PHP应用的开发者来说又是一个隐藏功能。这个内置的Web服务器不应该用于生产环境,但对于本地开发来说是个极好的工具。Laravel Valet 起初就是使用这个内置的服务器,但是在1.1.0版本后将其替换为Caddy(查看相关新闻)。 1、启动 这个内置的Web服务器很容易启动,打开终端(Windows下对应是cmd命令行),进入项目根目录,执行如下命令即可:

上述命令会新启动一个PHP Web服务器,地址是localhost,监听的端口是8000,当前所在目录就是这个Web服务器的根目录。 现在,打开浏览器,访问http://localhost:8000就可以预览应用了。在Web浏览器中浏览应用时,每个HTTP请求的信息都会记录到终端的标准输出中,因此我们可以查看应用是否抛出了404或500响应: 有时候我们需要在同一局域网中的另一台设备中访问这个服务器(例如iPad或本地虚拟机),为此,我们可以把localhost换成0.0.0.0,让PHP Web服务器监听所有接口:

要想停止Web服务器,可以关闭终端,也可以按Ctrl+C快捷键。 2、配置 应用常常需要使用专属的PHP配置文件,尤其是对内存使用、文件上传、分析或对字节码缓存有特殊要求时,一定要单独配置,我们可以使用-c选项,让PHP内置的服务器使用指定的配置文件:

3、路由脚本 PHP内置服务器明显遗漏了一个功能:与Apache和Nginx不同,它不支持.htaccess文件,因此,这个服务器很难使用多数流行的PHP框架中常见的前端控制器(单一入口文件index.php,用于转发所有HTTP请求,现在主流PHP框架如Laravel、Symfony都是这样)。 PHP内置服务器使用路由脚本弥补了这一缺憾,处理每个HTTP请求前,会先执行这个路由脚本,如果结果为false,返回当前HTTP请求中引用的静态资源URI,否则会把路由脚本的执行结果当做HTTP响应主体返回。换句话说,路由脚本的作用其实和.htaccess一样。 路由脚本的用法很简单,只需要在启动PHP内置服务器时指定这个PHP脚本文件的路径即可:

关于路由脚本,有兴趣的同学可以研究下Laravel Valet底层的server.php(https://github.com/laravel/valet/blob/master/server.php)。 4、判断函数 有时候需要知道PHP脚本使用的是PHP内置的Web服务器还是使用传统的Web服务器,这样方便我们为不同服务器设定不同的响应头。我们可以使用php_sapi_name()函数检查使用的是哪个PHP Web服务器,如果当前脚本使用的是PHP内置服务器,则该函数返回字符串cli-server:

5、缺点 PHP内置的Web服务器不能在生成环境使用,只能在本地开发环境中使用,这是因为其相比Apache或Nginx有诸多不足: 性能不佳。一次只能处理一个请求,其他请求会受到阻塞。如果某个进程耗时较长(数据库查询、远程API调用),则整个Web应用会陷入停顿状态。 支持媒体类型较少(这一点PHP 5.5.7以后有较大改进)。 路由脚本仅支持少量的URL重写,更高级则还是需要Apache或Nginx。   from:http://laravelacademy.org/post/4422.html

龙生   13 Aug 2017
View Details
1 231 232 233 432