随着在线攻击的增多,密码安全越来越重要。作为开发者我们要担负起安全管理、计算哈希和存储用户密码的责任,不管应用是简单的游戏还是绝密商业文件的仓库,都要做到这一点。PHP内置了一些工具,让保护密码变得更加容易,本节我们就来讨论如何根据现代的安全措施来使用这些工具。

1、密码保护三原则

绝对不能知道用户的密码

我们绝对不能知道用户的密码,也不能有获取用户密码的方式,如果应用的数据库被黑,你肯定不希望数据库中有纯文本或能解密的密码。任何时候,知道的越少越安全。

绝对不要约束用户的密码

如果要求密码符合特定的模式,其实是为不怀好意的人提供了攻击应用的途径,如果必须约束密码,我建议只限制最小长度,把常用的密码或基于字典创建的密码加入黑名单也是好主意。

绝对不能通过电子邮件发送用户密码

如果你通过电子邮件给用户发送密码,用户会知道三件事:你知道他的密码,你使用纯文本或能解密的方式存储了他的密码,你没有对通过互联网发送纯文本的密码感到不安。

我们应该在电子邮件中发送用于设置或修改密码的URL,Web应用通常会生成一个唯一的令牌,这个令牌只在设定或修改密码时使用一次(比如修改密码),通常我们把这个令牌作为设置或修改密码URL的一个参数,当用户访问这个URL时,应用会验证令牌是否有效,如果有效则继续操作,操作完成后,令牌失效,不能重复使用。

2、密码存储算法

关于密码存储的最佳实践是计算密码的哈希值,而不是加密用户的密码。加密和哈希不是一回事,加密事双向算法,加密的数据可以解密,而哈希是单向算法,哈希后的数据不能再还原成原始值,而且相同的数据得到的哈希值始终相同。

在数据库中存储用户的密码,要先计算密码的哈希值,然后在数据库中存储密码的哈希值,如果黑客攻入数据库,只能看到无意义的密码哈希值,需要花费大量的时间和NSA资源才能破解。

哈希算法有很多种(如md5、SHA1、bcrypt和scrypt),有些算法速度很快,用于验证数据完整性;有些算法的速度则很慢,旨在提高安全性。生成密码和存储密码时要使用速度慢、安全性高的算法。

目前,最安全的算法当属bcrypt,与md5和SHA1不同,bcrypt故意设计得很慢,bcrypt会自动加盐(salt),防止潜在的彩虹表攻击,bcrypt算法会花费大量时间反复处理数据,生成特别安全的哈希值。在这个过程中,处理数据的次数叫工作因子,工作因子的值越高,破解密码所需的时间越长,安全性越好。bcrypt算法永不过时,如果计算机运算速度变快了,我们只需提高工作因子的值。

3、密码哈希API

通过前面的介绍,我们知道在处理用户的密码时要考虑很多东西,好在PHP 5.5.0原生的哈希API(http://php.net/manual/zh/book.password.php)提供了很多易于使用的函数,大大简化了计算密码哈希值和验证密码的操作,而且,这个密码哈希API默认使用bcrpt算法。

开发Web应用时,有两个地方会用到密码哈希API:注册用户和用户登录,下面我们以Laravel提供的用户注册和登录为例,看看PHP密码哈希API时如何简化这两个操作的。

注:Laraval框架内置的用户注册和登录功能正是使用了PHP哈希API实现密码的存储和验证。

注册用户

用户注册在AuthController中完成,新用户的创建在该控制器的create方法中实现:

可以看到这里使用了Laravel提供的辅助函数bcrypt对用户提交的密码进行哈希并保存到数据库。bcrypt函数定义如下:

这里我们可以看出实际上是调用了别名为hash的服务提供者实例上的make方法实现哈希密码,进入HashServiceProvider,在register方法中我们可以看到hash对应的类为BcryptHasher,在该类中我们找到了make方法:

这里的核心是调用了PHP提供的password_hash函数,该函数接收三个参数,第一个是用户输入的密码值,第二个参数是使用的哈希算法(更多算法查看:http://php.net/manual/zh/password.constants.php),第三个参数可选,包括saltcost两个选项,分别表示干扰字符串(加盐)和前面提到的工作因子,工作因子可以随着硬件性能的提升而提升,不传的话使用随机加盐和默认工作因子(计算哈希值一般需要0.1~0.5s)。如果计算失败,抛出异常。

用户登录

在Larval中以在auth.php中使用session作为guards、eloquent作为providers实现用户登录认证为例(实际上默认设置就是这样),登录验证最终会走到EloquentUserProvidervalidateCredentials方法:

$this->hasher对应的实现也是BcryptHasher类,我们来查看它的check方法:

其中传入的第一个参数是用户输入的密码,第二个参数是用户注册时保存的密码哈希值,如果哈希值为空直接返回false,否则调用php提供的password_verify函数,该函数用于验证密码(纯文本)和哈希值是否匹配,匹配返回true,否则返回false。

重新计算哈希值

通过上述步骤用户已经可以实现登录认证了,但是登录前我们还需要检查现有的密码哈希值是否已经过期,如果过期,需要重新计算密码哈希值。

为什么要重新计算呢?加入我们的应用创建于两年前,那时候使用的工作因子时10,现在使用的是20,因为计算机的速度更快了,黑客也更聪明了。可以有些用户的密码哈希值仍然是工作因子为10时生成的,这时,登录认证通过后,要使用password_needs_refresh函数检查用户记录中现有的哈希值是否需要更新,这个函数可以确保指定的密码哈希值是使用最新的哈希算法创建的。如果确实需要重新计算生成密码的哈希值,要使用make方法生成新的哈希值并更新数据库中的原密码。

Laraval中目前并没有使用这一功能,但是在BcryptHasher类中已经提供了对应的函数:

PHP 开发者如何做好密码保护 & Laravel 底层密码存储和验证实现的更多相关文章

  1. Laravel底层原理系列

    Laravel 从学徒到工匠精校版 地址:https://laravelacademy.org/laravel-from-appreciate-to-artisan Advanced Applicat ...

  2. Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能

    Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...

  3. opesntack 底层共享存储 迁移配置

    底层共享存储在迁移配置: 每台compute 节点都需要配置一下 让nova用户可以登陆 usermod -s /bin/bash nova 设置nova 用户密码 echo "nova&q ...

  4. EXTJS 密码确认与验证

    extjs 框架是一个非常优秀的前端框架,提供了丰富的功能与炫丽的界面展示,在用 extjs 创建表单时,特别是在注册或修改密码的时候,要对密码进行确认,这里就密码确认一致性验证和大家分享自己的心得与 ...

  5. Oracle11g R2创建PASSWORD_VERIFY_FUNCTION对应密码复杂度验证函数步骤

    Oracle11g R2创建PASSWORD_VERIFY_FUNCTION对应密码复杂度验证函数步骤 运行测试环境:数据库服务器Oracle Linux 5.8 + Oracle 11g R2数据库 ...

  6. oracle 11g/12c 密码复杂度验证设置

    ############################################################################### ###### 11g ###### ## ...

  7. Python开发之用户密码存储

    在各种线上应用中,用户名密码是用户身份认证的关键,它的重要性不言而喻.一方面,作为保护用户敏感数据的钥匙来说,一旦被破解,系统将敞开大门完全不设防.另一方面,密码这把钥匙本身就是非常敏感的数据:大多数 ...

  8. 密码存储中MD5的安全问题与替代方案

    md5安全吗?有多么地不安全?如何才能安全地存储密码?... md5安全吗? 经过各种安全事件后,很多系统在存放密码的时候不会直接存放明文密码了,大都改成了存放了 md5 加密(hash)后的密码,可 ...

  9. Laravel 5.1 关掉csrf验证

    Laravel 5.1 关掉csrf验证 说明: Laravel默认是开启了CSRF功能,有时可能不能传递验证token,就需要关闭. 方法一(全局关闭): 打开文件:app\Http\Kernel. ...

随机推荐

  1. 再见丑陋的 SwaggerUI,这款开源的API文档生成神器界面更炫酷,逼格更高!

    一般在使用 Spring Boot 开发前后端分离项目的时候,都会用到 Swagger.Swagger 是一个规范和完整的框架,用于生成.描述.调试和可视化 RESTful 风格的 Web API 服 ...

  2. Saas系统架构的思考,多租户Saas架构设计分析

    ToB Saas系统最近几年都很火.很多创业公司都在尝试创建企业级别的应用 cRM, HR,销售, Desk Saas系统.很多Saas创业公司也拿了大额风投.毕竟Saas相对传统软件的优势非常明显. ...

  3. 企业级Docker容器镜像仓库Harbor的搭建

    Harbor简述 Habor是由VMWare公司开源的容器镜像仓库.事实上,Habor是在Docker Registry上进行了相应的企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:管理 ...

  4. autorelease基本使用

    1.autorelease基本概念 autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里 ...

  5. k8s之Dashboard插件部署及使用

    k8s之Dashboard插件部署及使用 目录 k8s之Dashboard插件部署及使用 1. Dashboard介绍 2. 服务器环境 3. 在K8S工具目录中创建dashboard工作目录 4. ...

  6. 强化学习中REIINFORCE算法和AC算法在算法理论和实际代码设计中的区别

    背景就不介绍了,REINFORCE算法和AC算法是强化学习中基于策略这类的基础算法,这两个算法的算法描述(伪代码)参见Sutton的reinforcement introduction(2nd). A ...

  7. JVM性能调优与实战基础理论篇-上

    Java虚拟机 概述 Java官方文档 https://docs.oracle.com/en/java/index.html JVM是一种规范,通过Oracle Java 官方文档找到JVM的规范查阅 ...

  8. idea导入mavenJar、mavenWeb项目

    两种项目都是一样的,都是maven项目,所以主要是找到pom.xml,项目最好先放在idea的工作目录下,且工作目录最好为英文 1.打开idea,选择import project 2.把项目放到ide ...

  9. node Cheerio 获取script脚本里的数据

    const cheerio = require('cheerio'); const $ = cheerio.load(html); // your html//如果有多少script脚本标签使用循环来 ...

  10. 从MVC到DDD的架构演进

    DDD这几年越来越火,资料也很多,大部分的资料都偏向于理论介绍,有给出的代码与传统MVC的三层架构差异较大,再加上大量的新概念很容易让初学者望而却步.本文从MVC架构角度来讲解如何演进到DDD架构. ...