当前位置:C++技术网 > 资讯 > 安全的网站登录机制应该这么设计

安全的网站登录机制应该这么设计

更新时间:2017-06-13 10:26:41浏览次数:1+次

    网站用户注册和登录,是网站用户使用的第一个入口。登录入口是通向服务器的一个关键地方。如果登录入口设计的不够安全,那么整个系统将面临着致命安全隐患。
    鉴于这个安全性非常值得关注,我现在将我项目中用到的一个相对安全的网站登录机制思路分享下,供大家一起学习思考,一起做出更好的更安全的登录系统。
    当然,这个机制并不是我个人设计的,而是学习使用别人设计的机制。我们的经验积累过程,不就是不断的吸收他人优秀的设计和经验,来丰富自己的经验嘛。然而如果只是看看,那样无法掌握。所以这次我系统的整理总结了一下,也分享出来。

        网站登录机制分为注册和登录。而登录涉及到密码。密码的安全是需要经得住考验的,另外就是额外的辅助手段,即登录码。首先的形成需要安全,所以在生成密码时会比较复杂。然后为了防止暴破,设计了登录码机制。有了复杂的密码和登录码机制,自然就安全的多了。不能说绝对的安全,因为根本就不存在绝对安全的系统。玩安全的都知道。

        原理流程示意图将在最后面放出,请先认真看看前面的分析,以免看图分心。


1.密码的形成
    密码的组成绝对不能只是用户填写的密码,特别不能明文密码保存。所以密码保存到数据库之前,得进行一步加密。至于采用不可逆的非对称加密还是可逆的对称加密,取决于登录验证机制如何设计。不可逆的可以采用MD5方式加密存储密码,可逆的可以采用AES加密。对称可逆的也就是可以加密,也可以解密,加密解密用同一个密码。而MD5不可逆加密,是无法反过来解密的。如果要对MD5进行密码验证,就只能按照同样的方法加密,然后比对加密后的结果,如果一致,则相同。
    MD5机制只能说确保了密码存储本身的安全,但是无法对抗暴破。因为根据常用密码依然可以算出MD5加密结果去比对。当然,你可以在对密码进行各种加强,以打破常用密码。比如常用密码有888888,那么在形成密码时,可以进行一个混淆,比如加入一段文字,或者先进行一步加密之类的。另外还可以防止多次频繁的登录。当然,最直接的就是在密码中加入一些无法预测的字符,和原始密码拼接,形成复杂的密码。如果是固定的加入一段文字,也可能被分析出来。这里提到的是别人得到数据库文件时对密码进行解码分析。这是最后一步的安全。但是一般情况是在登录时进行安全验证,只有很不幸导致服务器被黑,数据库被盗走了。如果密码设计的合理,密码依然是安全的。然而如果是固定的字符串,是可以分析出来的,这样再进行其他测试,也可能实现暴破密码。
    所以,相对更安全的方式是在生成密码时加入一段随机字符串。这样让密码变得没有规律,这样也就提高了安全性。因此,我们需要先对密码进行编码处理,得到统一长度的编码字符串,再混入随机字符串。这样得到的原始密码字符串,就是无规则的密码字符串了。比如我们可以先得到32位的字符串,然后再在后面拼接用Sha256编码后的64位密码字符串,一共96位长度字符串。这个密码够复杂了吧。使用Sha256是为了得到统一长度的字符串,确保后续的处理都统一。
    注册的时候,我们需要先在客户端或者网页前端先进行这样的密码处理,得到复杂密码字符串。但是这样还是不够的,因为密码在发送到服务器前,还会被拦截的。所以需要一个机制让密码发送安全,客户端这边能够做一些加密,只有服务器端才能解密的机制,这就是公私钥加解密机制。
    客户端或前端使用公钥加密,到服务器后,服务器用私钥解密。没有私钥,经过公钥加密的东西是没有办法的。我们可以使用RSA加密。
    经过RSA加密后的密码,发送给服务器,服务器再使用私钥解密,得到RSA加密前的非密文复杂密码字符串。这个复杂密码字符串还算是明文密码哦。所以我们要对这个密码进行对称密码加密,再存入数据库。我们可以使用AES加密。对称加密自然需要同样的密码来解密,所以后续在登录验证的时候,还需要AES解密得到复杂密码字符串。

2.登录码机制
    密码的形成已经很安全了,然而为了进一步提高破解难度,我们在每次登陆的时候,加入登录码的设计,来提高登录的安全性。登录码必须是每次都不一样的,这样我们还是用随机码来做。每次登录时随机码都不一样,所以也就给暴破大大提高了难度。
    登录码是要存储的数据库中的,供后续登录时进行比对。那么在注册时候,数据库要不要填写登录码呢?先来看我们的登录的流程。
    登录分为两个步骤,第一步是客户端上传用户名,服务器根据用户名查询用户的密码。此时数据库会先对注册时加密到数据库的密码进行AES解密,得到位加密的复杂密码。然后截取96位复杂密码后面64位字符串(前面32位字符串是随机码),然后再截取密码的后32位(当然你也可以截取前32位),这个密码作为AES加密的密码。因为AES加密密码这里用到了32位长度的密码,所以我们才要截断处理。然后我们再生成一个临时的随机码,用截取出来的密码作为AES加密密码加密随机数,得到一个加密后的随机数,发给客户端。然后随机数进行base64编码,然后存入数据库,替换掉注册时生成的登录码,供第二步登录验证。
    也就是说,每次登录在第一步就会更新登录码,所以还是很安全的。那么注册时要不要填写一个登录码呢?当然是要的。两次登录分别调用两次API,我们不能保证破解者会按照两次来使用。他可能直接调用第二次的API直接登录,这样第一步生成的登录码就不会执行。从而可以达到破解不变的登录码。如果注册时不填写登录码,也就是数据库中这个字段留空,那么通过第二次登录API直接传送一个空值,就可以实现登录了。所以这样是不行的。
    不过按照正常的设计,注册时填写的登录码在后续的登录是用不着的,只是作为安全性保护而填写的。所以,此时我们可以不必纠结于如何生成,只要安全就好。所以我们还是生成一个随机码,然后用密码的后32位或前32位加密,也就是和第一步登录时加密随机码得到的加密随机字符串一样的字符串当做登录码存入数据库。这个登录码生成规则和第一次登录生成的规则是一样的,所以可以代码复用,形式一致。

        而后续登录时都会更新登录码,所以自然安全有保障。就是直接绕过第一步登录,32位的随机码的复杂度,也可以让暴破很难。我们再可以对第二次登录做次数验证,失败之后,再刷新登录码。

    

        看完这么多的分析,应该自己心中也有一个流程图了,下面给出我制作的流程图,供你比对学习,对整个流程进行梳理。

    1.注册流程图

    注册流程图

    2.登录流程图

    登录流程图
    登录时客户端和服务器都是基于正确的密码的设计,前后端都进行AES加解密操作,用的都是用户的正确密码。第二步登录的登录码不需要进行额外的加密再传送给服务器了,因为这个字符串本身也需要进行合理验证。就算中途被拦截了,拦截的人也不知道登录码后续的登录码。因为登录码时刻都在变化。虽然拦截者无法直接登录,但是可以持续的监听。这个环节也可以对拦截的数据进行分析。所以后续的通信过程,也需要持续对内容进行加密,加密的密码用用户的密码就行了。
    这样在登录到通信过程,都以安全的形式在进行,网站的安全也就能够得到很好的保证。虽然我们没有使用SSL安全机制,使用HTTP依然可以实现安全的通信机制。实际上,SSL在内部会进行相关的加密,但是https对于很多应用场景应用的不是很好,比如很多浏览器会严格要求https的安全证书,很多会拦截提示什么的,体验有点不好。我们自己这样实现的安全机制,虽然是要自己动手保证安全,但是安全性还是可以得到保证,还是基于http的。你要知道,https协议对于搜索引擎支持的并不是很好,虽然有些引擎开始尝试支持,但是毕竟有一道关卡,对于网站的收录有所影响的。
    当然,安全没有定论,没有绝对安全的机制,没有绝对安全的系统。只能在一定时间内让安全性足够强就行了。还要不段的升级安全机制,确保系统持续的安全。