您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

构建安全的PHP应用

2025/1/2 19:52:22发布15次查看
译者序 2015年7月的一天,我正在feedly上悠然的阅读,突然出现一篇博客有介绍这本书,因为说的是我当时正在关注的php安全,所以认真看了那篇博客,顺着博客里的链接找到了这本书的官网,看起来很靠谱,而恰好我也需要,网站上有购买链接,一直到leanpub上我都在寻找是否有中文版可以购买,但没有找到,而后在twitter上联系了作者ben,问他关于中文版的事,遗憾的是还没人翻译过,当时就想这本书也不长,为什么我不来翻译一下,为中国的开发者做点贡献呢,当然也会收获小小的成就感,随后我们用邮件沟通了翻译的详细事项,只用了来回两封邮件,不过几百个单词,交流真简单明了,我爱上了这种高效简单的沟通方式!当然以后如果还有这样的机会,我想我还会继续行好事,做想做该做的,不问前程!如果有翻译不好的地方,可以随时邮件我,我会非常积极的修改,这本书在相当长的一段时间都会以电子版的形式存在,所以当我修改了你提出的问题后,一定会最快的同步线上,这样购买的所有人都会收到更新了,一起行好事吧!
写在前面 几年前我用php的codeigniter框架写了一个网页程序,但是这个框架并没有内置任何类型的身份验证系统。当然,这并不会难倒像我这样的一个好(懒惰)的开发者,我到处寻找一个靠谱的库来让我的应用拥有健壮的身份验证能力。然而令人失望的是我发现在codeigniter上并没有一个简洁、可靠并能满足身份验证需求的库。这让我走向了开发ion auth(可以从github找到)之路,它是为codeigniter开发的一款轻量级的身份验证库,并在为网页应用的安全上做了一个长时间的改革迭代,同时也帮助其他开发人员这样做。
多年之后,我们都已经换了很多的框架和语言,但是我仍然对被忽视的基础安全方面保持持续关注。让我们一起改变这个现状吧。我希望能够帮助大家再也不用生活在密码泄露的恐惧中,再不会为恶心的sql注入而担心,能够轻松的避免那些“黑客”的临幸。让我们都能确保可以每天按时下班回家,并能高枕无忧的做闭目佳人!
这本书将会是一本可以在具体项目中进行参考的快速阅读手册。意思是你可以在数个小时内快速看完并在你需要的时候随时查阅。我也会尽量使阅读本书变得更加有趣。
格式说明 若无特殊说明,在本书中缩进内的示例代码均为php。
以$符号开头的行
$ ls -al
是普通用户下在命令行下的命令示例
以#符号开头的行
# ls -al
是root用户命令行下的命令示例
服务器命令行示例会呈现*nix(centos, redhat, ubuntu, osx, etc)操作系统风格的样式
我会努力让示例代码有合适的换行,这样方法参数会在不同的行。这本书的代码风格虽然看起来比较奇怪但是比那些封装的代码更容易阅读。
勘误表 如果您发现任何问题都可以毫不犹豫的联系我的邮箱。
如果您有翻译问题也可以联系译者邮箱
示例代码 若无特殊说明,例子中的代码均为php。我会尽可能使用原生的php,除非它造成了太多的冗余。当使用原生php来阐述问题太啰嗦时,我也会使用laravel框架更优雅的风格让大家更容易理解。
一些代码过时或者不清楚,你可以在github repository找到更全的代码。
来吧!
关于作者 ben edmunds 带领开发团队做最前沿的网页和手机应用。他是一个活跃积极的领导者、开发者,也是在多个开发社区的演讲者。他已经在软件研发领域专业研究十余载并做过从机器人技术到政府项目的各种工作。
php town hall 播客的联合主持。波特兰php usergroup联合组织者。开源项目倡导者。
关于译者 张庆龙 技术上致力于web开发,主要使用php和ruby on rails,热衷使用mac进行开发和日常工作。热爱生活,喜钓鱼,爱表演,好搞小幽默。主要活动在京津冀地区。
第一章 - 不相信任何用户,格式化所有的输入! 我们从一个故事说起,麦克是俄克拉何马州一个私立学校的系统管理员。他的主要工作是保持学校的网络畅通和服务器稳定。最近他开始为学校开发一个可以自动完成各种任务的网页应用以供内部使用。他没有参加过正规的培训而且是刚从一年前开始编程,但是他对自己的工作自我感觉良好。他了解一些php基础而且已经为学校开发了一个有够稳定的客户关系管理系统。还有大量的功能等着添加,但是基本功能已经完备。麦克甚至由于精简业务和节省学校开支获得了来自院长的称赞。
一切都很好,但是有一天一个特别的学生带来了噩梦。这个学生的名字是little bobby tables。这天,大乔在管理员办公室打电话给麦克问为什么系统崩溃了。经过排查,麦克发现那个存有所有学生信息的数据库表完全消失了。好家伙,little bobby的全名竟然是robert'); drop table students;--,太尴尬了。这时候数据库还没有备份,这是麦克即将要做的一件事,但是还没开始。这回麦克摊上大事儿了。
sql 注入 真实的故事 虽然在真实的世界里名字中包括危险sql语句的可能非常小,但是像这种sql注入漏洞却每天都在发生:
2012年,linkedin由于一个隐藏的sql注入漏洞泄露了600万用户数据
2012年,雅虎!泄露了450,000的用户密码
2012年,nvidia的400,000个密码被盗
2012年,adobe的150,000个密码被盗
2013年,eharmony泄露了大概150万的用户密码
sql注入的原理 如果你可以不加修饰的接受用户直接输入的内容,那么一个歹毒的用户就可以传入一个奇葩的数据,直接改变你的sql语句。
假设你的代码像下面这样:
mysql_query('update users set first_name=' . $_post['first_name'] . ' where id=1001');
你可能希望生成的sql语句为:
update users set first_name=liz where id=1001;
但是如果有个歹毒的用户把他的名字写成:
liz, last_name=lemon; --
那生成的sql语句就变成了下面这样:
update usersset first_name=liz, last_name=lemon; --where id=1001;
现在你所有的用户的名字都被改成了liz lemon, 这岂不是很悲催。
如何防止上面的事发生 一个有效预防sql注入的方法是格式化输入(也被称为转义)。你可以为每个特别的输入转义。或者更好的方法被称作参数约束,这是我强烈推荐的方法,它拥有更高的安全性。使用php的pdo类,你的代码现在变成下面这样:
$db = new pdo(...);$query = $db->prepare('update users set first_name = :first_name where id = :id');$query->execute([ ':id' => 1001, ':first_name' => $_post['first_name']]);
使用约束的参数就意味着每个值都能被恰当的引用,转义,且只匹配一个值。需要牢记的是,参数约束虽然可以保护你的sql语句,但是却不会在插入数据库之后保护输入的数据。记住,任何数据都有可能是具有破坏性的。你仍然需要剔除and/or这些容易被遗忘且稍后会展示在用户页面上的内容。你可以在存入数据库的时候就进行处理,或者在展示的时候处理,但是不要省略这重要的一部。我们会在接下来的章节详细探讨。
现在你的代码稍微多了一点,但是更安全了。你不用担心再被另一个little bobby tables弄糟你的日子。参数约束已经很帅了是吧,知道还有什么很帅么?是我!哈哈。
最佳做法和其他解决方案 存储过程是另一个防范sql注入的方法,它是在数据库上编译的。用上存储过程以后就意味着你不太可能被sql注入,因为你的数据一开始就没有通过sql语句的形式传输。一般来说,存储过程是让人苦恼的,有以下几个主要原因:
难以测试
把业务逻辑放到了应用外(即数据库层)
不易版本控制,因为他没在你的代码而是在数据库
在需要修改这部分逻辑的时候直接限制了能胜任之人的数量(为什么存储过程在我们日常开发中不多见?)
客户端 javascript并不是验证数据的好办法。它很容易被篡改或者被一个只具备初级互联网知识水平的歹毒用户回避。跟我重复:我永远不会只依靠javascript验证;我永远不会只依靠javascript验证。你当然可以使用javascript来提供实时交互并做更好的用户体验,但是为了表达对神的真爱,还是需要在后端增加处理逻辑来保证一切都是合法的。
mass assignment(批量赋值) mass assignment是一个非常能提高开发速度的实用工具,但若使用不当也会带来严重问题。
假如你有一个user的模型,你需要对它进行一些更改。可以依次更新每个字段,或者可以把所有需要修改的值一次性通过表单传过去。
比如下面是你的表单:

然后使用后端的php代码处理提交的表单。如果使用laravel框架,代码是下面这样:
$user = user::find(1);$user->update(input::all());
真是又快又好是吧?但是如果有个歹毒的用户修改了表单,给了她自己管理员权限呢?

我们的后端代码就会错误的改变了用户的权限。
听起来又有一个愚蠢的问题需要解决了,但这却是目前大多数开发者和网站可能深受其害的。最近,大家应该都听说了一个开发者扬言ruby on rails很容易被这个的漏洞利用。egor homakov最初向rails团队提交问题说rails在刚被初始化之后是不够安全的,他这个bug很快就被关掉了。核心团队认为要避免这个问题的方法对新手来说都是常识(attr_accessible),这个问题属于开发者而不是rails应该做的(大家一般都会这样想)。homakov觉得好心被当成了驴的某些器官,非常生气,就黑了github上的rails账号(github是用ra...
你是如何应对类似的攻击呢?具体实现方法还要看你使用的框架和语言,但是你有几个通用的选择:
彻底关掉mass assignment
给可以安全被批量赋值的字段加白名单
给那些危险的加黑名单
根据你的实现方法,这些也可以被同时使用。
在laravel框架你可以在models中添加一个$fillable变量做可被批量赋值的白名单字段:
$id, //我们知道它是个整形 ':first_name' => $_post['first_name']]);
上面这样并没什么意义,因为id是我们自己定义的,我们本来就知道他是整形,但是如果id是在别的表单传递过来的,它就有了让我们心如止水的意义。
php提供了一系列可以转换的类型:
64)仍没有发现漏洞。
由于没有被blowfish大量的审查,bcrypt只在内部使用。blowfish加密自1991年以来一直被认为是安全的,但使用它弱键是一个已知的缺陷。它是基于一个加密算法给bcrypt带来了一层额外的开销,使它优于标准的哈希算法,换句话说bcrypt设计的较慢。但慢是一件好事!
在这我推荐bcrypt, sha-256 或者 sha-512是可以作为目前有效的安全备选的。可以用来作为衍生算法的一部分,比如pbkdf2或用php的crypt()函数实现。
bcrypt 大多数人觉得bcrypt是一个新丁而没有被广泛的使用。其实它是在1999年发布的,这明显是老头儿了。bcrypt是基于blowfish密码的衍生方法,它是迭代的所以由于生成哈希的开销关系他可以防止暴力破解。
尽管事实上很多密码学家都在大量关注bcrypt但目前仍还有公布的漏洞。一直到写这篇文章的这么长时间以来(2014),bcrypt被认为是密码安全的。
bcrypt在加密纯文本密码的时候有72字符的限制。所以经常有切掉多余字符的做法或者只支持最大72个字符的验证。
bcrypt也是我们后面例子中选择的密码加密方案。
scrypt scrypt是个新成员。在2012年发布,它是一个在内存方面加强的衍生算法。理论上来说scrypt在高内存消耗条件下是个更安全的算法。但是它太新了我个人不太推荐在现在使用。
在密码界新的一般都不太受欢迎,因为它并没有接受足够的像那些老算法那样相同等级的攻击和审查。虽然最近爆了一些漏洞但这并不意味着scrypt不够安全,但还是要远离理论上的安全优势。
值得注意的是scrypt已经被很多流行的加密货币使用到他们的采矿业务,显著的有莱特币和狗狗币。这意味着它也会像它的前辈一样受到大量注意。
存储 这节会比较短,嗨起来!不管你使用什么系统存储你的密码哈希,不论使用关系数据库,密钥存储器,锁箱,袜子抽屉,或者文件系统;使用不限长度的文本字段或者我推荐使用varchar(255)。你的哈希算法会生成最大长度的字符串所以你并不用为攻击者脱你的数据库而担心。不同的哈希算法会生成不同长度的字符串所以你要根据你的算法来设置字段长度。我比较喜欢设置较长的字段以防之后用别的哈希算法,而不抠门在那多出的存储空间。
使用bcrypt你的哈希最大是60个字符。所以理论上来说你可以设置一个varchar(60)的字段但并不兼容之后的修改。为了你的密码还是别在乎那几个字节了,搞个text字段或者用varchar(255)吧,你值得拥有。
验证 唯一需要验证的是密码的最小长度。你应该允许使用字符,空格,短语等,你的用户可以设置他们想要的任何密码。好的短语是比较推荐的,correct horse battery staple”总比mynewpassword”要强。你只需要担心密码不够复杂,不够长。
为了给所有人你的爱,别做像通过javascript限制复制粘贴的傻事。如果人家用户使用密码管理工具你应该让其用的更爽。如果你这么做了,你的用户会觉得很不爽,骂声当然就来了。
有个需要注意的是bcrypt只能使密码的前72位有效所以你可以从技术上进行约束。这虽然会稍微有些限制你的用户但是对你未来选择其他哈希算法带来了方便。如果你的用户对一个74个字符的密码记得特熟练,你可以只使用它的前72位,总好过让他想个新的出来。有些代码会推荐先使用标准哈希算法(sha-256, sha-512, 等)然后再使用bcrypt对其哈希结果再做一个来解决这个长度问题。这真是一个有够完美的解决方案,但我不太推荐,因为72个字符加上一个有效的盐足以让你的密码在现代科学上有够安全了。
放在一起说说 我们刚说了一些基础知识,现在我们一起敲点代码吧。
开始我会带你用传统的/弃用的做法随后我也会带你使用php 5.5或更高版本的新方法来搞这些。原因有下:
我希望你能够了解底层原理而不是只看到一个封装的方法
你可能正在使用一个低版本的php,但是我还不想放弃你
下面的场景是注册新用户。我们需要生成一个随机盐,做他们的密码哈希,然后把他们都存在一个虚拟的数据库中。作为未来的身份验证使用。
< php 5.5 如果你还在用低于5.3.7版本的php那么你至少要为了保证最起码的安全升级到5.3.7来。如果你实在不升我不知道还能推荐给你什么。升级之后你会发现很多老版本的bug都被修复了。在我们的场景中,bcrypt在5.3.7之前就有缺陷。我们会在下面的例子中使用$2y$前缀,他会一直作为前缀参数。意思就是说他已经更新了漏洞修复和新的逻辑。
第一步我们要先生成一个随机盐。根据你系统安装的扩展使用php你有很多方法去做这件事。比如:
$passwordhash ));}else { //错误提示}
现在我们已经给密码做了哈希并存入了数据库。注意我们为什么没有存盐呢?是因为crypt()会保存返回的哈希中我们选择的算法,密码的哈希值,以及盐。
我们已经有注册用户了,比如他要登出站点(好大的胆子!)然后一会又回来了,他们需要登录。登录是简单美好的,我们只需要验证他的文本密码和我们存在数据库中的哈希。
user()-where(array( 'email' => $_post['email']))->row(); //验证他们是否相等 $pass = $_post['password']; if (crypt($pass, $user->pass) === true) { $valid = true; }//其他的验证,错误处理等等... if ($valid === true) { //验证有效}
如果我们把之前生成的哈希放在crypt()的第二个参数他将自动选择算法并使用相应的盐来生成哈希与存在数据库中的密码哈希进行对比。
>= php 5.5 在php5.5.后引进了新的密码哈希函数使得很大程度简化了密码操作流程。目的在于隐藏那些复杂的逻辑并使php开发者使用默认的函数就能保证安全而不依赖于所有的开发者都需要掌握这些密码知识,换句话说他们正在努力使我的书越来越不好卖,尴尬。
严肃的说,应该尽可能的使用php的密码函数。它提供了内置的最新版本哈希并加带附加的安全检查而我们这里并没有包含,比如保护定时攻击(timing attacks).
我们下面就讲一下php 5.5语法的步骤。我们将用到password_hash函数来生成密码的哈希,这个函数会自动创建随机盐所以我们会省一些步骤。我们看下代码:
user()->create(array( 'password' => $passwordhash));
下面是在登录的时候验证密码
user()-where([ 'email' => $_post['email']])->row(); $pass = $_post['password']; if (password_verify($pass, $user->pass) === true) { $valid = true; }if ($valid === true) { //附加逻辑}
像上面你看到的那样,php 5.5中的新密码函数可以让你的生活简单清爽。这个函数的另一个优点是它内置于php所以你在未来可以一直依赖它,而不是自己持续的追最新密码算法的版本。这很吸引人对吧,把它的利弊交给php核心团队,留更多的时间让自己去做其他更精彩的事情。
当你想要实现身份验证模块的时候确保参考php文档来保证代码的时效性。当然,也应该知道其他有效密码函数的优势比如password_get_info()和password_needs_rehash().
你还在用php 5.3么?错过了新版5.5的所有乐趣?别急,anthony ferrara帮你做了一些事情。他的password_compat库在php 5.3.7实现了新的密码函数,你可以从这里下载[anthony's github]
我极力推荐你使用这个库而不是自己写,因为它已经被充分测试过了我们完全可以信赖它。
残忍的暴力攻击防护 你可以拥有最完美的密码哈希,用了所有的安全措施,但是当残忍的攻击者不断的攻击你的登陆页直到他获得正确密码的做法是没有用的。暴力攻击就是攻击者使用软件不断的尝试不同的密码直到他登录为止。
防护这种攻击很简单,遗憾的是我发现很多站点并没有做的很好。所以我们该如何做好呢?那就是当有人以这种方法获取密码的时候就让他靠边等着去吧。
一个人试着登录,失败了。然后又重试,又失败了。再来,呵呵。这时候你就让他靠边等一分钟再来。好了,这就是最简单的解决办法,也是最有效的办法。如果一个攻击者每分钟才能试三次密码那么他将等到天荒地老,还攻击什么呢。你的用户安全了。不一定是限制三次,三、五、十都不错;我个人推荐每分钟不超过10次。
你还可以扩展一下,限制ip。只允许某一ip登录所有用户x次而不是只限制登录一个用户x次。还要确保包含恰当的错误提示以及合理的重试时间,企业团体用户一般都会抛出一个公共ip地址所以你还不能因为一个坏人而惩罚数千个合法的用户。
当然,把相同的逻辑用在api验证上,让攻击者认识到不同的地方也会是一样的结果。不管你在前端用了什么安全措施,也要把他合理的移植到api上去。
升级遗留的老系统 现在房间里有个大象。抓住他?大象哎。一晚上也抓不到吧。那么我们如何升级在使用md5密码并没加盐的原有系统呢?
我可以给你两个选择:
1 - 在每个用户登录的时候默默的帮他用bcrypt升级他的密码。他们在什么都不知道的时候你的数据库就已经更新到了安全的密码。
2 - 使用bcrypt在原有的md5串上再做一次哈希。新密码就是md5和bcrypt的二重加密了。
第一种升级办法 第一种方法是迁移新身份验证方案的传统建议。而且在大多数情况下是最好的办法。你可以像下面这样做来实现:
user()-where([ 'email' => $_post['email']])->row(); if ($user->pass_hash_algo === 'bcrypt') { //他们已经登录过并已经完成了升级,我们可以验证登录 }else { //验证一下老密码 $oldhash = md5($_post['password']); if ($oldhash === $user->pass) { //用原密码生成一个新的哈希值 $newhash = password_hash($_post['password']); //保存到数据库并标记完成 $user->pass = $newhash; $user->pass_hash_upgraded = 'bcrypt'; $user->save(); $valid = true; } //...}
这样改一下登录逻辑你的用户将在登录的时候自动升级他密码的新哈希。积年之后这次升级将轻松的用上了我们推荐的哈希算法。之后scrypt可能会变成被接受的标准那时候你的升级将轻松易得。
第二种升级办法 第二种办法虽然解决的不清澈但是一经使用立刻生效。上面的第一种方法在一段时间还会保留一些不安全的哈希密码直到所有的用户都登录过但这种办法一旦上线立刻能使你的数据安全,你不会丢失任何一夜的睡眠。这节你会直接在所有的密码哈希上使用bcrypt再做一次哈希。你的最新哈希是在md5基础上使用了bcrypt之后的强大哈希。这增加了复杂度因为你每次都需要同时使用bcrypt和md5直到永远,会笨重很多年。
一共包括两步,第一步写个类似下面的脚本扫一遍你的现有数据库。告诉我你会用导出的数据库而不是在生产服务器上干这件事。对吧?因为那会让我们都伤心…你还要在每条记录上加一个状态。下面是个例子,别复制粘贴啊,咳咳...
users()->result(); foreach ($users as $user) { $newhash = password_hash($user->pass); $user->pass = $newhash; $user->save(); }
现在数据库已经升级了我们还要改下注册方法
user()->create([ 'password' => $passhash]);
当然登录方法也要同样的将校验文本密码改成验证md5密码
user()-where([ 'email' => $_post['email']])->row(); //在使用bcrypt之前先使用md5方法 $md5pass = md5($_post['password']); //验证密码的正确性 if (password_verify($md5pass, $user->pass) === true) { $valid = true; }//其他的验证等
好了,我们终于安全了 这就是本节的全部了。虽然还有更多关于密码的知识但你必须知道的已经在这里了,我可能不会写密码的附加章节或者高阶内容了。敬请期待下一章吧,我们会讲url的限制,安全的文件操作,确保没人能看到你的数据。
资源 如果你对本章的密码学感兴趣我强烈建议你看下bruce schneider的研究成果。你应该读一下他的书applied cryptography,在加密方面很权威。
我还喜欢关注php社区其他成员的工作,anthony ferrara倡导从php5.5内置密码哈希函数。这使得我们在未来缺省构建安全的php应用方向迈了一大步。
第四章 - 身份验证, 权限控制, 安全的文件操作 erica在一个小型的制造业公司做程序员以及it支持。他最近被分配开发公司的员工系统,带领公司从纸质时代飞到数字世纪。
第一步是让员工扫描文档,用电子存储替代纸质表格。
归档系统开发的一切顺利,系统由所有文档组成的数据库清单构建,还能过滤像部门,日期,标签这些。没什么复杂逻辑,erica就想保持简单。
文档会以用户的部门和职位为过滤条件呈现给用户(比如,某人,管理部,主管)。几个月以来都相安无事,但有一天还是迎来了不快。一个机密文件出现了漏洞。经过调查发现一个不满的员工得到了一个只有高级管理员能浏览的文件访问权。这个员工把此文件泄露给了竞争公司听说轻而易举的拿到了竞标。
这是怎么发生的呢?erica花了一个周末去研究,突然,他发现了,这是多么的明显,但他没有想到要防范。
在他的系统中,文件上传的时候是以数据库表中的id命名的。上传了一个pdf文件可能叫13424.pdf,又上传了一个doc文件,就被名为13425.doc,诸如此类。erica虽然已经使文件不可见,但他没考虑到文件可以直接被浏览器下载。用户可以轻易的通过猜测自增id下载到敏感的文件。
这小故事略长,但只要你努力你也能讲出这么长的故事。我曾经告诉一个妇女我是kevin costner,他就信了,因为我也信。
身份验证 控制敏感数据的第一步就是身份验证,你要确保每个用户并不是只靠自己说说就能证明他是谁。
这里我们会阐述一下上一章中密码验证的代码实例,然后会讲下用户的有效登录过程。
pass) === true) { $valid = true; } //其他操作等... if ($valid === true) { //成功登录 //存储session session::put('user', $user->id); return true; } //登录失败 session::put('user', null); return false; }}
我们记下了用户的成功登录态,只存储了他的用户id。但他的登录并不是说他可以在你的应用里为所欲为。
权限控制 除了判定用户是否登录有效,我们还要判定他是否有某些页面/部分/功能的访问权限。
我们从基础说起。麻瓜和管理员。麻瓜是拥有少量访问权限的普通用户。管理员就是可以访问所有地方的人物。管理员可以增删用户,管理文章等。非常重要的是普通用户 - 麻瓜 - 不能操作这些功能
不同的框架在验证使用权的时机各不相同。在laravel中,symfony是首选。在大多数系统中你可以只简单的调用构造函数。下面是个例子;你可以根据情况改变实现方式。
我们先在usermodel中添加一个获取用户信息的方法
groups) === false) { //做好错误处理 die('not authorized'); } } //其他的管理员专用操作}
你通常会在你的controllers/routes/或其他地方抽象出一个控制层。这一层会梳理你的路由恰当的拥有视图的访问级别。比如,/admin/*只能是admin用户组访问。post和put请求只能编辑使用。delete请求只能管理员使用。
关键是,每个页面都应该检查用户的访问级别并确定他们是否被授权请求各种方法。你不仅需要去设想一个用户可以看到一个表单并能post到正确的地址,并授权执行了动作。我们还应该防止恶意用户提交恶意数据改变你的数据库,他在一开始就不应该看到那个页面。
别在安全的身份验证上掉以轻心,认真起来!你会为你自己和其他开发者节省不必要的开发时间也减少了未来的头疼。
验证重定向 在你的应用流程中,经常会通过表单发送一个post请求到你的控制器,之后验证数据,执行动作,然后重定向到应用的下一步页面。
如果你重定向的地址包含敏感数据,用户其实可以通过简单的发送一个请求跳过你的期望流程直接到最后的页面,并跳过了你的验证步骤。
当然有很多办法来控制啦。第一种办法就是不再使用重定向。大多数时候当你想要用重定向的时候,你可以换成直接调用下个方法,比如把下面的替换一下:
改成直接调用edit方法而不是使用重定向:
_edit(1);}
在这个例子中,_edit()方法应该是一个保护或私有方法,这样就不能跳过前面的步骤而用url直接进入了。
如果实际上你需要一个其他的地址,而且你有很多入口都会指向这个目的地,那么你就必须验证那些必须的步骤已经被执行过。
使用一个有过期时间的session变量(一般叫做flash)通常是不错的办法。
在你的edit函数处, 你应该验证刚刚的参数
模糊处理 你有没有听说过security through obscurity(隐式安全)”的术语?虽然不是所有的地方都有效,但有时候真的好用。大多数应用的数据库都会在每个表中存一个id的字段来做主键。这个id后面被用在系统的各个地方。比如url,表单,还有api用来表示我们需要的数据。
有时候,试想,你并不想对你的用户展示真正的数据表id。也许你在做一个新产品的时候也不希望用户知道他原来才刚刚是第十三个用户。也许你的数据是公开的但你并不想被机器人蠕虫轻易的爬去。
这时候,你可以混淆id到非自增的字符串但可以翻译为你的id。如果你是这样做的:

该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product