php记住账号,php实现记住登录

本文探讨了三种实现记住密码功能的安全方案。第一种方案使用用户ID作为令牌,但存在安全风险;第二种方案采用随机字符串,但易受时序攻击;第三种方案使用选择器和验证器组合,避免时序攻击并确保安全性。在验证过程中,使用hash_equals()函数防止攻击,并详细描述了登录、验证和取消记住登录的流程。
摘要由CSDN通过智能技术生成

流程

1.用户通过点击“记住密码”,提交登陆表单传递给服务器。

2.服务器生成唯一标识token,保存到数据库

3.写cookie,设置失效时间(这样token就保存到了客户端)

4.如果用户登陆失效,服务器取客户端token进行校验

5.token与服务器保存的token一致,且没有失效,则判定用户登录成功

6.token与服务器保存的token不一致或超过失效时间,则判定用户需要重新登录

方案一

用用户id来作为token,如remember_user=1337,这样等于把用户id暴露了出来。 这样一来,可以不断尝试不同的用户id来登录其他人的账号,甚至可以登录管理员账号,相当危险!!

方案二

使用一个随机字符串作为token。

function generateInsecureToken($length = 20)

{

$buf = '';

for ($i = 0; $i < $length; ++$i) {

$buf .= chr(mt_rand(0, 255));

}

return bin2hex($buf);

}

mt_rant其实并不安全,如果你要生成随机数,可以使用以下几个方案

1.RandomLib[^1]

2.random_bytes($length) (PHP 7, or available in PHP 5 via random_compat[^2])

3.Raw bytes read from /dev/urandom

4.mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)

5.openssl_random_pseudo_bytes($length)

可以这么写

function generateToken($length = 20)

{

return bin2hex(random_bytes($length));

}

这个方案会有时序攻击的风险。 如果你的token=WBWgm2oMFxsiGRGQNJ6n8gtN3gOuQ2wjN8ZRjZtU0Mn 如果你是通过数据库来校验

SELECT * FROM auth_tokens WHERE token = 'WBWgm2oMFxsiGRGQNJ6n8gtN3gOuQ2wjN8ZRjZtU0Mn';

或者通过从数据库取出token,在进程中做简单校验

$getToken = $_GET[‘token’];

if ($getToken == $token) {

//success

} else {

//fail

}

这时有人按以下步骤修改他的cookie

1.第一次把第一个字节从W改为X

2.第二次把最后一个字节从n改为o 第二次的校验时间要比第一次的校验时间要短,这样用户可以不断修改尝试来确认更改的字符是否正确,就是一次时序攻击。参考It’s All About Time. 这个时间差异仅在纳秒级有意义。 这不是一个简单或容易的攻击,但是我们写一个存在风险的进程是完全没有意义的。

方案三

在token中不留下任何有用的信息(甚至服务器时间)给攻击者。 使用selector:validator来取代单一的token,通过selector在数据库中去取出validator,这样可以防止不可避免的时序风险。

从数据库取出token,进程中使用hash_equals()来做校验,因为hash_equals()能够防止时序攻击。

生成token

if ($login->success && $login->rememberMe) { // However you implement it

$selector = base64_encode(random_bytes(9));

$authenticator = random_bytes(33);

setcookie(

'remember',

$selector.':'.base64_encode($authenticator),

time() + 864000,

'/',

'yourdomain.com',

true, // TLS-only

true // http-only

);

$database->exec(

"INSERT INTO auth_tokens (selector, token, userid, expires) VALUES (?, ?, ?, ?)",

[

$selector,

hash('sha256', $authenticator),

$login->userId,

date('Y-m-dTH:i:s', time() + 864000)

]

);

}

验证

if (empty($_SESSION['userid']) && !empty($_COOKIE['remember'])) {

list($selector, $authenticator) = explode(':', $_COOKIE['remember']);

$row = $database->selectRow(

"SELECT * FROM auth_tokens WHERE selector = ?",

[

$selector

]

);

if (hash_equals($row['token'], hash('sha256', base64_decode($authenticator)))) {

$_SESSION['userid'] = $row['userid'];

// Then regenerate login token as above

}

}

实际例子

这里没有把uc记住登陆接口用异步请求去处理,主要因为我们系统并不都在同个主域名下,所以如果要实现全系统统一记住登陆处理,只能跳转到uc,在uc设置cookie。

1.记住登录

sequenceDiagram

participant 系统A

participant UC

系统A-->>UC: 请求异步登录接口校验

UC->>系统A: 返回登录校验结果

Note left of 系统A: 失败则结束流程

系统A-->>UC: 跳转到记住登录接口

Note right of UC: 1.生成token

2.写入数据库

3.设置cookie

UC->>系统A: 跳转回系统A首页

Note left of 系统A: 完成

2.校验登录

sequenceDiagram

participant 系统A

participant UC

系统A-->>UC: 跳转到校验记住登录接口

Note right of UC: 校验cookie及有效期

Note right of UC: 校验失败

UC->>系统A: 跳转回系统A登录页

Note left of 系统A: 完成

Note right of UC: 校验成功

1.生成新token

2.写入数据库

3.设置cookie

UC->>系统A: 跳转回系统A首页

Note left of 系统A: 完成

3.移除记住登录

sequenceDiagram

participant 系统A

participant UC

系统A-->>UC: 跳转到移除记住登录接口

Note right of UC: 1.删除cookie

2.删除数据库token

UC->>系统A: 跳转回系统A首页

Note left of 系统A: 完成

资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值