你的登录接口真的安全吗?
日期: 2020-09-09 分类: 跨站数据测试 318次阅读
前言
当您学习编写程序时,第一行代码是hello world。但是,当您开始学习WEB后台技术时,许多人的第一个功能是编写登录名(轻声:我不认识其他人,我还是这样)。
但是,当我采访许多工作经验短的学生或与之交流时,我发现许多学生在简历上写了:负责项目登录/注册功能模块的开发和设计,但是他们都很简单。实现了功能逻辑,并且在安全性方面考虑不太多。本文主要是与您聊天。设计登录界面时,它不仅是功能上的实现,而且还是我们需要考虑的安全性。
安全风险
暴力破解!
只要该网站在公共网络上公开,就很有可能成为目标网站。尝试使用这种简单有效的方法:
以多种方式获得网站的用户名后,编写一个程序遍历所有可能的密码,直到找到正确的密码为止
伪代码如下:
密码字典
password_dict = []
登录接口
login_url = ‘’
def attack(username):
for password in password_dict:
data = {‘username’: username, ‘password’: password}
content = requests.post(login_url, data).content.decode(‘utf-8’)
if ‘login success’ in content:
print(‘got it! password is : %s’ % password)
那么我们如何预防这种情况呢?
验证码
我是聪明的学生想到的,当密码输入错误一定次数后,我可以添加验证码验证!例如,我们设置为当用户的密码错误3次时,要求用户输入图像验证码以继续登录操作:
伪代码如下:
fail_count = get_from_redis(fail_username)
if fail_count >= 3:
if captcha is None:
return error(‘需要验证码’)
check_captcha(captcha)
success = do_login(username, password)
if not success:
set_redis(fail_username, fail_count + 1)
伪代码不考虑并发性,实际开发中可以考虑锁定。
这确实可以过滤掉一些非法攻击,但是使用当前的OCR技术,普通的图像验证码确实很难有效地阻止机器人(我们为此遭受了很多苦难)。搜索公共垂直编号:rHub,[]获得前端和后端的入门教程!当然,我们也可以花钱购买类似于第三方公司提供的滑动验证的验证方案,但是它不是100%安全的并且会被破解(痛苦的一课)。
登录限制
当时,有些学生说我可以直接限制异常用户的登录操作。当密码输入错误一定次数后,将直接拒绝用户的登录。稍后恢复。例如,当我们将一个帐户设置为以10个错误登录时,该帐户的所有登录操作将在5分钟内被拒绝。
伪代码如下:
fail_count = get_from_redis(fail_username)
locked = get_from_redis(lock_username)
if locked:
return error(‘拒绝登录’)
if fail_count >= 3:
if captcha is None:
return error(‘需要验证码’)
check_captcha(captcha)
success = do_login(username, password)
if not success:
set_redis(fail_username, fail_count + 1)
if fail_count + 1 >= 10:
失败超过10次,设置锁定标记
set_redis(lock_username, true, 300s)
嗯,这确实可以解决用户密码被爆破的问题。但是,这将带来另一个风险:尽管攻击者无法获取该网站的用户信息,但它可能阻止我们网站的所有用户登录!
攻击者只需要遍历所有用户名(即使没有用户名,也可以是随机的)来登录,那么这些用户将始终被锁定,从而导致普通用户无法登录该网站!
IP限制
然后,由于不可能直接定位用户名,因此我们可以处理IP。如果直接阻止了攻击者的IP,一切都会好起来的。我们可以设置为,当某个IP下调用登录界面的错误次数达到一定数量时,将禁止该IP的登录操作。
伪代码如下:
ip = request[‘IP’]
fail_count = get_from_redis(fail_ip)
if fail_count > 10:
return error(‘拒绝登录’)
其它逻辑
do something()
success = do_login(username, password)
if not success:
set_redis(fail_ip, true, 300s)
这也可以在一定程度上解决问题。实际上,许多电流限制操作都是在IP上执行的。例如,niginx的限流模块可以在一个单位时间内限制IP的访问次数。
但是这里仍然存在问题:
例如,许多学校和公司现在使用相同的出口IP。如果直接通过IP限制它,则可能会意外杀死其他普通用户。
拥有如此多的VPN,攻击者是完全可以的。您可以在IP被阻止进行攻击之后切换VPN
移动验证
没有更好的方法来阻止它?当然有。我们可以看到,近年来,几乎所有应用程序都允许用户绑定他们的手机。一是国家实名政策要求,二是手机与身份证基本相同,并且基本上可以代表一个人的身份。如此多的安全操作都基于手机验证,因此也可以登录。
当用户输入密码超过3次时,要求用户输入验证码(最好使用滑动验证)。
如果用户输入密码超过10次,则弹出手机验证,要求输入 用户使用手机验证码和密码双重认证
手机验证码防刷卡是另一个问题。我不会从这里开始。我将在有时间的时候谈论我们将来要做的事情。
伪代码如下:
fail_count = get_from_redis(fail_username)
if fail_count > 3:
if captcha is None:
return error(‘需要验证码’)
check_captcha(captcha)
if fail_count > 10:
大于10次,使用验证码和密码登录
if dynamic_code is None:
return error(‘请输入手机验证码’)
if not validate_dynamic_code(username, dynamic_code):
delete_dynamic_code(username)
return error(‘手机验证码错误’)
success = do_login(username, password, dynamic_code)
if not success:
set_redis(fail_username, fail_count + 1)
我们结合了上述方法,并增加了手机验证码的验证方式,基本上可以防止相当数量的恶意攻击者。但是没有一个系统绝对安全,我们只能尽可能增加攻击者的成本。您可以根据网站的实际情况选择适当的策略。
中间人攻击吗?
什么是中间人攻击
***中间人攻击(缩写为MITM)***,简单来说,A和B处于通信过程中, 攻击者通过嗅探和拦截来获取或修改A和B的通信内容。
举个栗子:小白派快递员去小黄,途中经过快递点A,小黑躲在快递点A上,或者干脆打开快递点B装成快递点A。然后秘密地打开快递站。小白快递员给小黄看里面的东西。您甚至可以离开小白的快递员,打包一角钱的盒子,然后寄给小黄。
在登录过程中,如果攻击者嗅探从客户端发送到服务器的登录请求,则可以轻松获得用户的用户名和密码。
HTTPS
防止中间人攻击的最简单,最有效的操作是替换HTTPS并修改网站中的所有HTTP请求以强制使用HTTPS。
***为什么HTTPS可以阻止中间人攻击? ***
HTTPS实际上在HTTP和TCP协议之间添加了SSL / TLS协议,以确保数据的安全传输。与HTTP相比,HTTPS具有以下特征:
内容加密
数据完整性
身份验证
具体的 HTTPS 原理这里就不再扩展了,大家可以自行 Google
加密传输
除了HTTPS,我们还可以手动加密和传输敏感数据:
可以在客户端对用户名进行加密,并在服务器端进行解密
可以在客户端将密码设置为MD5传输 防止暴露密码的纯文本
其他
除了上面我们讨论的那些以外,实际上还可以考虑许多其他任务,例如:
操作日志,每个用户的登录名和敏感信息 需要记录操作日志(包括IP,设备等)
异常操作或登录提醒。使用以上操作日志,我们可以根据该日志进行风险提示。例如,当用户登录,更改密码或异常登录时,可以通过短信
提醒用户。拒绝弱密码注册或更改密码时,不允许用户设置弱密码
防止遍历用户名。注册某些网站时,输入用户名后,将提示用户名是否存在。这样,存在网站所有用户名将被泄露(仅遍历界面)的风险,并且需要在交互或逻辑上加以限制
…
后记
现在 国家继续颁布各种法律,越来越重视用户数据。作为开发人员,我们还需要做更多的工作来保护用户数据和用户隐私。希望我能为您们提供一些帮助。
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
精华推荐