大家对登录并不陌生,几乎所有的接入系统都需要登录。因为系统不知道访问的是谁,所以你需要告诉系统你是谁,你需要证明你真的是你,怎么证明呢?向系统出示你的密码,因为只有你有密码,你有这个密码,你才能证明你真的是你,这就是登录。看似简单的几个步骤,其实涉及到很多安全问题。密码存储安全首先,我们来看一下密码存储安全问题。系统服务器需要存储用户密码,以便用户登录时验证密码的正确性,但存储存在泄露风险,如数据库被盗、服务器被黑、内部员工泄露数据、被黑客攻击等。数据库和其他风险。所以我们需要认真考虑如何安全地存储用户密码。我认为作为一名软件开发工程师,严格禁止以明文形式存储密码是常识。那么如何解决密码不能明文存储的问题呢?也许你会说md5?是的,md5可以。那么md5属于什么?它是一种单向哈希算法。单向哈希算法主要是通过算法生成一个摘要来解决密码无法被清除的问题。例如:md5(123456)=e10adc3949ba59abbe56e057f20f883e这样虽然可以解决密码未知文化,但还是存在安全问题。因为现代计算机的计算能力太强了,一秒钟可以计算十亿次,可以通过穷举比对破解密码。这就是所谓的彩虹表攻击。解决被彩虹表攻击的问题对密码也有一定的要求,比如密码的复杂度,不同类型字符的组合,生成摘要时加点盐防止穷举破解密码等。但这安全吗?不够。一种算法远远不能满足安全要求,比如md5(md5(md5(密码+salt))),现在往往采用自适应的方式存储密码,可以设置重复计算10000次,而salt使用随机生成的16位以上的字符串。虽然这种方法的性能不会很好,但是对于密码生成和摘要存储来说,性能差往往是件好事。毕竟用户注册或者修改密码只是一次性的操作,用户可以接受,但是对于黑客来说,却是致命的,黑客已经从每秒产生几百万甚至几千万的md5值变成了只每秒一个。黑客想要破解密码。从现代计算机的计算能力来看,需要几千年的时间。目前推荐的密码存储算法不再是md5,推荐使用BcryptScryptpdkdf2算法。(很多可以通过MD5/SHA值进行反向查询,因为存储了大量的彩虹表。)密码传输安全解决密码存储安全,然后我们再来看密码传输安全。有人会说使用https可以解决网络传输的安全问题,但这还不够。浏览器和认证服务器之间的请求可能会经过一层或多层网关,比如nginx、zuul、springcloudgateway等,很多系统会在网关处安装证书,设置https协议。浏览器到网关是加密的,但是到认证服务器的网关还是使用http协议。攻击者可以盗取这个链接的明文密码,那么全链接https就可以解决问题了吗?还不够,这些网关可能会接触到明文密码,存在密码泄露的风险。有些网关不是我们的。负责,不能保证别人会开后门取出明文密码,或者安全意识不高的程序员在打印日志的时候不小心把明文密码打印出来。那么如何解决这个问题呢?我们可以采用在浏览器传输密码之前对密码进行加密的方法。加密方式分为对称加密和非对称加密。对称加密:加密和解密使用相同的密钥。如DES、AES非对称加密:加密和解密使用不同的密钥,一个叫公钥,一个叫私钥,用公钥加密的数据只能用对应的私钥解密,比如RSA。如果采用对称加密方式,浏览器在调用登录API前需要先获取认证服务器的密钥,获取密钥后对密码进行加密传输。经过的网关只能得到密文,密码到达认证服务器。服务器再通过密钥对密文进行解密,得到密码的明文,然后进行密码验证。但是,存在安全问题。浏览器通过网关获取密钥。如果网关也将密钥和密文打印到日志中,攻击者也可以通过日志获取明文密码。既然对称加密不可取,那么我们来看一下非对称加密。浏览器在登录前通过网关获取认证服务器的公钥,用公钥加密,最后将密文发送给认证服务器,再用私钥解密得到明文密码进行密码认证。这样网关只能得到公钥和密文,不能解密。即使打印到日志中,攻击者也无法获取到明文密码。但这安全吗?如果攻击者使用网关中的密文直接调用认证服务器中的登录接口,认证服务器也可以用私钥解密并成功登录。所以我们需要加一些限制:保证密文有过期时间,并且只能使用一次。浏览器在获得认证服务器的公钥后,携带用户名给认证服务器。认证服务器生成一个随机数并将其与用户名相关联。随机数只保存5分钟,随机数和公钥返回给浏览器。浏览器使用随机数加密码一起通过公钥加密调优登录API。认证服务器通过私钥解密,得到明文密码和随机数,验证随机数的有效性和合法性。如果一切正常,则正常登录。比对完成后立即删除随机数后的随机数,不正常则拒绝登录。即使攻击者获得了密码密文、公钥和随机数,也只能在网关正常请求登录前5分钟内发起登录攻击,但这难度太大了。另外,认证服务器确保客户端是由网关或可信服务发起的请求。认证服务器可以对客户端进行白名单限制。方法有很多,这里就不一一赘述了。但是现在安全吗?并不真地。如果攻击者攻破网关,当浏览器向认证服务器请求获取公钥时,网关返回攻击者下发的公钥。用户输入账号密码后,虽然浏览器对数据进行了加密,但是数据到了网关,攻击者通过解密自己的私钥得到明文密码,然后通过明文在登录页面正常登录密码,也可以登录成功。因此,浏览器也需要做安全验证,验证公钥的合法性。认证服务器可以使用CA组织颁发的公钥。认证服务器和浏览器都信任CA组织(做安全必须要相信一些东西,如果什么都不信任,就不能做安全,永远不会有安全问题)。CA机制验证公钥的合法性,避免中间人篡改公钥的问题(不是很清楚,比如什么是CA组织,CA组织为什么可信?话题太多了说到这里,有兴趣的可以去看看《密码学与网络安全》等书籍或者一起讨论研究)。密码安全吗?还是不够。例如,如果黑客知道你的密码长度,他就可以不断调整登录或修改密码的界面试错,总会测试出正确的密码。因此,需要对任何可以验证密码合法性的接口进行频率限制。如果连续5次错误登录,将被锁定5分钟,然后再错误5次后将被锁定半小时,以防止黑客尝试密码。但这种做法也存在问题。例如,竞争对手公司不断使用用户的账号和错误的密码登录,导致用户的账号一直处于锁定状态,正常用户无法使用,违反了安全上的可用性。然后需要添加ip限制和验证码机制。为了用户体验,可以让首次登录的用户可以正常登录。出错后需要使用验证码登录,如果账号被锁次数超过5次,同一个ip登录错误次数过多,该ip会被加入黑名单。.PasswordlessSecurity密码存在很多安全问题,复杂的密码对用户来说也很麻烦,所以使用passwordless技术。没有密码安全吗?虽然现在可以使用指纹登录和人脸登录,但是新的安全问题也会随之而来。密码需要保密,但可以通过照片获取指纹。美国国防部一位官员拍照的时候露出了大拇指,然后大拇指有清晰的指纹(拍照的时候不要剪刀或者咔哒)喜欢,最好把指纹对着自己,手动狗头)。还有不确定性。刷脸登录时,如果光线太暗或太亮,脸部受伤,或化妆,是否能保证登录成功?登录时是否可以区分相似面孔的人?如果不这样做,就会破坏账户的唯一性,以后的审计也会有问题。另一个问题是它不能被修改。当密码泄露时,您可以更改密码,但您的指纹已经被用作登录凭据,只需更换手指即可。如果你用了所有十个手指,你应该用你的脚趾吗?当然,没有密码肯定更好。密码使用起来更方便快捷。随着技术的发展,这些问题会得到解决,但是安全问题会更多。再来看session安全(密码安全问题各种各样,篇幅有限,不再赘述)。在存储会话ID并完成安全登录后,用户不可能每次操作都输入密码。因此,系统需要记录用户的登录状态,也称为会话状态。通常的做法是通过系统保存会话。session存储用户信息,生成一个随机数sessionId,将sessionId返回给浏览器,保存在浏览器的cookie中。下次用户访问系统时,携带cookie,系统通过cookie找到session,就知道用户是谁了。对于集群服务,用户第一次登录,访问服务器A,将session保存在服务器A,下次访问服务器B,但是服务B没有session。它认为用户没有登录,提示用户登录,这是一个bug。我们可以通过将每个服务器标识为具有会话来解决此问题。session存储在redis中,登陆时session存储在redis中,然后从redis中取出session。或者每个服务器都有一个session,每个服务器的session同步也可以解决这个问题。无论使用哪种方法,都存在安全风险。给出了sessionId。不管sessionId是随机数生成的字符串还是加密后的字符串,黑客都不管。黑客只关心这个字符串代表用户的会话状态。黑客不需要得到密码,只需要得到这个字符串,就可以模拟用户进行诈骗、转账、发表非法政论等违法活动。保护sessionId不被非法使用与保护密码一样重要。大多数情况下sessionId是保存在cookie中的,我们先了解一下cookie。这是登录okta后生成的cookie之一。它具有名称、值、域、路径、Expires/Max-Age、Httponly、Secure等属性。下面是其中的一些。域:cookie对其有效的域。该cookie的域为thoughtworks.okta.com,浏览器只有在访问thoughtworks.okta.com下的API时才会将cookie发送到后台服务器。该值可以包含子域。例如,当域设置为okta.com时,访问thoughtworks.okta.com时也会带上cookie。HttpOnly:当值为true时,告诉浏览器不能通过js访问cookie,只有在向后端发送请求时才会携带cookie。Secure:当该值为true时,告诉浏览器只有当访问协议询问https的API时才会携带cookie。Expires/Max-Age:cookie有两种类型,localcookie和sessioncookie。如果设置了cookie的过期时间,则为本地cookie,不设置为sessioncookie。sessioncookie的特点是它没有特定的过期时间,当浏览器关闭时就会被清除。本地cookies即使关闭浏览器也不会被清除,到时候会自动清除。这就是为什么有的系统关闭浏览器重新打开浏览器后需要重新登录,而有的则不需要。了解了cookie的几个特点之后,我们再来看看攻击者常用的几种攻击方式:XSS攻击、CSRF攻击。SessionID传输安全(1)XSS攻击称为跨站脚本攻击,是指将用户的输入与正常的html+js+css拼接,变成攻击性的html+js+css。浏览器可能无法识别攻击性的html+js+css,按照正常逻辑执行代码,可能导致攻击者窃取cookie(XSS还有其他危害,这里只讨论session识别)。如果黑客在html中插入隐藏表单,通过document.cookie()获取浏览器中的cookie,将其作为参数自动向攻击者后台API发送post请求,攻击者就可以获取到用户的cookie,还可以获得sessionId。该方法可以通过设置cookie的HttpOnly为true来阻止js获取cookie的值。这样就避免了通过跨站脚本攻击获取sessionId。(2)CSRF攻击称为跨站请求伪造。XSS攻击是指代码执行攻击脚本对本网站的影响。CSRF攻击是用户打开其他网站,浏览器执行其他网站的攻击脚本,而对本网站造成损害。例如,当我在浏览器中登录银行网站进行转账操作时,浏览器调用https://www.xxx.com/transfer?toBankId=123456&money=100,我的账户减少了100100元收到短信后被扣款。这时,一封标题为“你想获得力量吗?”的邮件来了。内容是一个链接。我点开这个链接,看到url是www.yyy.com/index.htm,立马又收到一条短信。我的帐号很低。我付了1000元,我刷新下一页,少了1000元。打开页面查看源码,发现一个隐藏标签,src=https://www.xxx.com/transfer?toBankId=123456&money=1000。这意味着每次刷新页面时,浏览器都会执行一次https://www.xxx.com/transfer?toBankId=123456&money=1000GET请求。大多数浏览器都有同源策略(协议\主机\端口组成源),其中一个限制是同源网页会共享cookie。但是,浏览器对html标签有一个白名单,img就是其中之一。get请求可以通过img标签的src发送。因为访问xxx(银行)域名,携带cookie,银行认为是合法请求,转账成功。.既然img是get请求,转账等高危操作改成post接口不行吗?也不行,因为form表单的post请求也在白名单里。CSRF攻击之所以成功,是因为攻击者可以完全伪造用户的请求,可以通过让攻击者无法伪造来解决这个问题。转账时,要求用户再次输入密码或输入验证码,可以解决CSRF攻击。这可以用于传输操作。对于发表评论等操作,每次都要求用户输入密码或验证码,是非常差的用户体验。(3)还有Referer检查。浏览器发送请求时,携带Referer头,也就是网站url中的域名。异常转账时,虽然调用了www.xxx.com的API,但referer值为www.yyy.com。只要在服务器端验证Referer值,就可以判断这是否是CSRF攻击。这种方式还有一个问题,就是第三方(浏览器)是完全信任的。对于低版本浏览器,已经有办法篡改Referer值,高版本浏览器目前无法篡改。如果用户使用低版本浏览器,Referer检查将无法保证安全。那么有没有其他办法可以解决CSRF攻击的问题呢?来看看okta是如何解决这个问题的。我们登录okta成功后,打开网页源码查看html,搜索token可以看到span中保存了一个token值。我们新建一个tab页,打开浏览器f12查看网络请求。可以看到请求头中有x-okta-xcrftoken这个头。这就是解决CSRF攻击的方式:CSRFToken方式。csrftoken的工作原理是用户登录成功后,服务器生成token并保存一段时间,返回给浏览器,浏览器保存在html标签中。当用户操作访问后端API时,将token放入请求头中。后端通过验证token的合法性来判断是否是CSRF攻击。这种方法起作用的关键点是攻击者无法获取目标网站的html。最近在想一个问题,就是如果黑客同时发起XSS攻击和CSRF攻击,这个方法会不会也失效?黑客通过XSS攻击获取CSRFtoken,攻击者立即向目标用户发送钓鱼邮件,目标用户点击链接,打开网站时,首先从黑客那里获取CSRFToken,并携带CSRF用于发起CSRF攻击的令牌。还有一个前提就是浏览器版本太低,没有Referer,那么攻击能成功吗?(我是不是多虑了?)cookie+session有那么多安全需要考虑,那么没有cookie+session就不会有那么多问题吗?流行的jwt可以实现sessionless登录认证,但是jwt也存在各种安全问题。【本文为专栏作家《ThoughtWorks》原创稿件,微信公众号:Thinkworker,转载请联系原作者】点此查看该作者更多好文
