认证授权与SpringSecurity_概念篇
# 认证授权与SpringSecurity_概念篇
# 身份校验
# session
在网络传输过程中,对请求进行身份认证是非常重要的安全措施,原因包括但不限于以下几点:
- 保护隐私和敏感数据:身份认证能确保只有授权的用户才能访问他们自己的私人数据,如个人信息、银行账户详情、电子邮件等敏感内容,防止非法用户冒充他人获取数据。
- 防止未经授权的访问:没有身份验证机制的系统容易受到攻击,攻击者可以随意访问、修改或破坏系统资源,造成严重的数据泄露或服务中断。
- 满足合规性要求:许多法规和行业标准强制要求企业对用户身份进行核实,确保数据和交易的安全性。
- 实施访问控制:根据用户的角色和权限,身份认证有助于实施细粒度的访问控制策略,保证每个用户只能执行与其权限相符的操作。
但此时有个问题,在Web应用中,HTTP请求本身是无状态的,即服务器无法记住两个连续请求之间的关联。这意味着单纯依靠HTTP协议,服务器无法知道发出请求的客户端是谁,也就无法维持用户的登录状态。
如果要做到上述的身份验证,就意味着每次请求都需要进行验证,对应到现实生活就是你每做一件事,工作人员就要来询问一次你的身份信息,这显然是不合理的?太麻烦了,身份验证应该只做一次就好。
为了解决上述问题,于是Session(会话)机制
出现了。
Session的引入提供了以下解决方案:
- 持久化用户状态:当用户登录成功后,服务器会创建一个Session并在服务器端保存用户的会话状态信息(如用户ID、角色、权限等)。每个Session都有一个唯一标识Session ID。
- 状态追踪:服务器将Session ID通过某种方式(常见的是Cookie)发送给客户端(浏览器),客户端在后续请求中会携带这个Session ID,服务器通过识别Session ID来关联用户的会话状态,进而实现状态管理。
- 安全性提升:Session还可以结合加密技术和过期时间设置,进一步提高用户认证的安全性。例如,Session ID可以是随机生成且经过哈希或加密处理的,且服务器端定期清理过期的Session,以防止长时间的未授权访问。
因此,Session机制为Web应用提供了用户身份识别和状态保持的能力,实现了用户登录一次后在整个会话期间内无需反复登录即可访问受保护资源的功能,增强了网络服务的安全性和用户体验。
Session ID除了最常见的存储在客户端Cookie中外,还可以通过以下几种形式实现传递和管理:
- URL重写(URL Rewriting):
- 在每个动态生成的网页URL后面添加一个查询字符串或者路径参数,其中包含了Session ID。例如,
http://example.com/page?session_id=123456
或http://example.com/session/123456/page
。这种方式下,用户点击链接或提交表单时,Session ID会被自动包含在请求中发送给服务器。- 隐藏表单字段(Hidden Form Field):
- 在HTML表单中嵌入一个隐藏的input元素,其值为Session ID。当用户提交表单时,Session ID随之发送到服务器。
- 自定义Header:
- 在HTTP请求头中添加自定义字段来携带Session ID,但这通常需要客户端程序(如JavaScript)或特定的应用层协议配合完成。
- Flash存储或其他客户端存储技术:
- 对于非浏览器客户端,或者为了兼容那些禁用了Cookie的浏览器,也可以使用Adobe Flash Player的本地共享对象(Local Shared Object,LSO)或其他类似的技术存储Session ID,并在HTTP请求中以适当的方式传递。
需要注意的是,除Cookie外的其他方法可能存在安全性较低、可移植性差等问题,而且对于现代Web应用而言,URL重写和隐藏表单字段已经较少使用。
# session的缺陷
每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会越来越大。
并且因为认证的记录是被保存在内存,这意味着用户下次请求还必须要请求在该台服务器上,这样才能拿到授权的资源。
如果应用部署在多台服务器上(分布式应用),则意味着每台服务器都要存储session,这极大的浪费了服务器资源,才外还有信息同步的安全问题也要考虑,不能A服务器中的session消除了,B服务器中的还在。
如果是基于cookie来进行用户识别的,当cookie被截获,用户就会很容易受到跨站请求伪造的攻击。
因此在分布式系统中,session是不太够用的。
# Token的诞生
为了解决在分布式系统中身份认证的问题,Token出现了。
Token——它是服务器通过验证用户名/密码或其他凭据后,生成一个唯一的特殊字符串,我们称之为令牌(能够证明我们的身份)。
在后续的请求中,客户端向服务器发送这个Token字符串,服务器接收到后,通过解码并验证其各个组成部分来确认Token的有效性。token比起session它不用存储在服务器内存,即使在分布式系统中也不会有上述占用服务器内存过多,分布式中的一致性问题了,因为它实际是存储在客户端的(但也有情况会存储在服务端-扩展中会说明),身份确认则是通过服务器用特定算法解析并验证token的正确性来保证。
此外,它的引入还带来了诸多优势:
- 身份验证(Authentication):
- 用户首次登录时,服务器通过验证用户名/密码或其他凭据后,生成一个唯一的Token并发送给客户端。后续请求中,客户端只需携带此Token,服务器就可以通过验证Token确认用户的身份,而不是每次都查询数据库中的用户凭证,从而降低了数据库查询的压力,也提高了系统的性能。
- 状态管理(Statelessness):
- 在Web应用中,传统Session机制需要在服务器端维护用户的会话状态,这在集群环境中可能导致状态同步问题。Token通常设计为无状态的,服务器不需存储Token的状态信息,仅需验证Token的有效性,这就简化了服务器端的状态管理和扩展性问题。
- 跨域资源共享(Cross-Origin Resource Sharing, CORS):
- Token有助于克服同源策略限制,允许不同域名的服务之间共享认证状态,例如单点登录(Single Sign-On, SSO)场景。
- 移动和多平台支持:
- Token适合于各种客户端,包括Web浏览器、移动设备应用程序等,提供了跨平台统一的身份验证解决方案。
- 可配置的有效期(Expiration Time):
- Token可以设定有效期,过期后自动失效,从而实现了更灵活的用户会话管理,同时也增强了安全性。
JWT(JSON Web Token)就是Token的一种具体形式,它不仅携带了身份信息,还利用数字签名保证了Token的安全性和完整性,进一步优化了上述问题的解决方案。
最初的的,传统的Token,就是一个无序的字符串。用户登录成功生成对应的令牌,key:令牌
,value:userId
(用户信息),后来为了更安全,开发者们制定了一个标准,或者说设计出了一种特殊格式的字符串也就是JWT。
总的来说,Token的出现是为了改善用户体验,提高系统效率,增强安全性,并适应分布式和微服务架构的需求。
# token跟session的区别
Token和Cookie通常都可以放在HTTP头部中传输,但是Token在安全性方面的优势主要体现在以下几个方面:
- 跨域安全性:
- Cookie默认遵循同源策略,即只能由设置它的同一源访问,但这同时也意味着如果恶意站点尝试发起跨站请求,浏览器会自动携带Cookie到目标站点,增加了
CSRF(跨站请求伪造)
的风险。 - Token则可以在客户端(如JavaScript)控制何时何地发送,可以选择不在跨域请求中自动发送,减少了CSRF攻击的可能性。
- Cookie默认遵循同源策略,即只能由设置它的同一源访问,但这同时也意味着如果恶意站点尝试发起跨站请求,浏览器会自动携带Cookie到目标站点,增加了
- 存储位置与暴露风险:
- Cookie通常存储在客户端,且有可能受到浏览器安全设置的限制,如HttpOnly属性阻止了JavaScript读取Cookie内容,Secure属性要求Cookie只在HTTPS连接上传输。
- Token可以选择多种存储方式,如
LocalStorage
、SessionStorage
、或者在某些情况下也可存入Cookie,但即便存入Cookie,Token本身并不依赖于浏览器自动发送,而是由前端程序控制何时发送至服务器,这种方式更加灵活且可控。
- 无状态性与服务器负载:
- Cookie常常与服务器端的Session关联,服务器需要保存Session ID并在接收到Cookie后查找对应的Session数据,这种有状态的处理方式容易遭受DDoS攻击,且不利于水平扩展。
- Token通常是无状态的,服务器不需要保存任何状态信息,Token包含了必要的用户信息,服务器直接验证Token即可,减轻了服务器压力,同时提高了系统的扩展性和可用性。
- 加密与自包含信息:
- JWT(JSON Web Token)等类型的Token可以携带经过加密和签名的信息,这些信息在传输过程中即使被截获也不能轻易破解和篡改。
- Cookie也可以加密,但在默认情况下并不具备这种特性,而且Cookie的内容相对简单,不像Token那样可以包含复杂的认证和授权信息。
- Token刷新与生命周期管理:
- Token的生命周期完全由应用逻辑控制,可以设计成一次性使用、短期有效或长期有效,并能轻松实现Token的撤销和刷新机制,对于敏感操作可以采用短期Token配合刷新Token的方式降低安全风险。
综上所述,Token相比于Cookie,在很多场景下提供了更精细的安全控制手段,尤其在现代Web应用和服务端API设计中,Token已经成为一种主流的身份验证和授权机制。
# token的扩展
在大多数现代的安全认证机制中,尤其是在RESTful API的设计和实现中,当涉及到用户身份验证时,通常会将token放在HTTP请求的头部。具体来说,通常的做法是将token置于
Authorization
头部字段中,其格式通常是:
Authorization: Bearer <token>
这里的
Bearer
后面跟着的是用户的授权令牌(access token)。这种做法有助于提高token的安全性,因为它不会像放在URL查询参数中那样容易暴露在浏览器历史记录、服务器日志等地方,而且对于HTTPS请求,头部信息在传输过程中会被加密,进一步增强了token的安全性。另外,这也有利于遵循HTTP协议标准,比如OAuth 2.0和其他安全规范,这些规范都推荐或要求将token放在请求头部。
Token并不一定只存储在客户端,有时它也会存储在服务端。是否存储于服务端则取决于所使用的认证机制和具体的应用需求。
Refresh Tokens:在某些OAuth 2.0或其他认证框架中,服务端会生成一个短期的Access Token(存储在客户端)和一个长期的Refresh Token(服务端和客户端都可能存储)。当Access Token过期时,客户端可以用Refresh Token换取新的Access Token,此时服务端必须存储Refresh Token以验证兑换请求。
黑名单机制:为了能够及时注销用户或撤销某个Token,服务端可能会存储Token的黑名单。当发现Token被盗或需要立即失效时,将其加入黑名单,服务端在验证Token时检查黑名单即可。
总之,服务端是否存储Token取决于具体的认证方案和技术选型,无状态的Token(JWT就是无状态的Token)设计倾向于避免在服务器端存储Token,而有状态的认证系统或者为了实现额外安全机制时,服务端可能需要存储相关Token信息。
# 三方登录
三方登录(也称为第三方登录或社交登录)在现代互联网应用中变得越来越普遍了。背后的原因主要有以下几个
- 简化用户体验:对于用户来说,记住并管理多个不同网站或应用的账号和密码是一个繁琐的任务。通过使用三方登录,用户可以直接使用他们已有的社交账号(如微信、QQ、微博等)进行登录,无需再注册新的账号或记住新的密码。这大大简化了用户的登录流程,提高了用户体验。
- 提高用户信任度:第三方平台(如大型社交平台)通常拥有较高的用户信任度和品牌影响力。当用户看到可以使用这些平台账号进行登录时,他们往往会更加信任并愿意使用该应用。
- 减少账号被盗风险:通过第三方平台进行登录,用户的密码不会直接暴露给应用开发者。这降低了用户账号被盗用的风险,因为第三方平台通常会采用更高级别的安全措施来保护用户信息。
- 方便数据共享:通过三方登录,应用可以方便地获取用户的部分公开信息(如昵称、头像等),从而简化用户信息的填写过程。同时,这也为应用提供了更多的用户数据,有助于进行更精准的个性化推荐和服务。
尽管三方登录带来了诸多便利,但相应的也带来了一些潜在的风险和问题,如当用户使用第三方登录时,他们通常需要同意第三方应用访问他们的个人信息。如果用户没有仔细阅读权限请求或理解它们的意义,可能会无意中分享过多的个人数据。造成用户隐私泄露、数据滥用,甚至如果用户的第三方账户密码被泄露,那么攻击者可能会利用这些凭证来访问依赖该第三方登录的所有服务。等....
为了更安全更可靠的实现三方登录,大家制定了一系列安全协议。其中OAuth2就是最为重要的之一。
# OAuth2
OAuth2全称为Open Authorization 2.0,它是一个网络协议。
在RFC 6749中我们可以知道,OAuth2——它是面向解决第三方应用的认证授权协议
。OAuth2提供了一种安全的方式,让第三方应用能够获取访问用户数据的权限,而无需直接获取用户的敏感信息。
OAuth2协议中包含了几个关键角色,包括客户端(Client)、资源拥有者(Resource Owner)、授权服务器(Authorization Server)和资源服务器(Resource Server)。客户端是请求访问用户数据的第三方应用;资源拥有者通常是用户本人;授权服务器负责处理授权请求并颁发访问令牌;资源服务器则存储了用户的实际数据,并会根据访问令牌来决定是否允许客户端访问这些数据。
OAuth2提供了多种授权模式,包括授权码模式、简化模式、用户名密码模式和客户端模式等。其中最为经典也最为常用的就是授权码模式
。
# JWT
JWT,全称JSON Web Token,是一种开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于在各方之间作为JSON对象安全地传输信息。
简单来说,JWT就是一个包含用户信息的字符串。这个字符串由服务器生成并发送给客户端,客户端可以在后续请求中附带这个字符串以证明用户的身份。
JWT的构成:JWT,这个字符串包含了三个部分:头部(Header)
、负载(Payload)
和签名(Signature)
。
头部:通常包含了JWT的类型(即JWT)和所使用的签名算法(如HMAC SHA256或RSA)。
负载:包含了有关用户的信息,如用户ID、用户名、角色等。这部分还可以包含其他自定义的信息。
签名:是对头部和负载的编码后进行签名,以确保数据的完整性和发送者的身份。
头部:
{ "alg": "HS256", "typ": "JWT" }
1
2
3
4经过 Base64URL 编码后变为:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
负载:
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
1
2
3
4
5经过 Base64URL 编码后变为:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
签名: 签名是使用一个
密钥
和前面两部分(头部和负载)的 Base64URL 编码后的字符串计算得出的。签名算法(例如 HMAC SHA-256)会对这两部分加上密钥进行计算。
最后,三部分合起来就是JWT的最终形态
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
而它的验证也比传统的token更加严格和安全,它使用签名验证
- 使用与生成签名相同的算法和密钥对头部和负载进行重新签名。
- 比较这个新生成的签名与 JWT 中提供的签名是否一致。
- 如果不一致,则说明 JWT 被篡改,应拒绝该令牌。
第三部分即签名(Signature)是通过使用一个密钥(通常称为 secret)和前两部分(头部和负载)的 Base64URL 编码字符串来计算得出的。这个密钥(secret)对于确保 JWT 的完整性和验证至关重要,它存储在服务器端:
- 签发方 (Issuer): 签发 JWT 的服务器需要保存 secret 以创建 JWT 的签名。
- 验证方 (Verifier): 验证 JWT 的服务器也需要保存 secret 以验证 JWT 的签名。
JWT通常用于身份验证和授权。一旦用户通过了身份验证,服务器会生成一个JWT并返回给客户端。客户端可以在后续的请求中附带这个JWT,服务器则可以通过验证JWT来确认用户的身份和授权。此外,它还也可以增加一些额外的其它业务逻辑所必须的声明信息
JWT的一个关键优势是其无状态性,即服务器不需要保存任何关于会话的信息。这使得JWT非常适合用于分布式系统或微服务架构中,因为每个服务都可以独立地验证JWT而无需与其他服务通信。
需要注意的是,JWT并不直接定义如何获取或验证令牌,它只是一种表示和传输信息的方式。在实际应用中,JWT经常与OAuth2等协议结合使用,以实现更完整的身份验证和授权功能。
综上所述,JWT是一种紧凑的、自包含的、可验证的信息传输格式,通常用于身份验证和授权场景中。
# SSO
随着信息技术的发展和企业信息化程度的加深,企业内部开始部署各种业务系统,如ERP(企业资源规划)、CRM(客户关系管理)、HRM(人力资源管理)、财务管理等。这些系统往往由不同的供应商提供,且各自拥有独立的用户账户体系和登录机制。随着系统数量的增长,员工需要记忆和管理的账户凭据增多,登录过程繁琐,工作效率受到影响。分散的登录机制不仅增加了密码泄露的风险,还使得安全策略难以统一实施。
企业需要一种解决方案能够整合这些系统的身份管理,实现用户在不同系统间的一次登录、多系统访问。
于是乎单点登录SSO(Single Sign-On)出现了。
# sso的优势
Sso相比一般登录方式具有以下显著优势:
用户体验优化:
- 减少登录次数:用户只需记住一个用户名和密码组合,无需为每个应用单独记忆和输入凭据,减轻记忆负担。
- 简化登录过程:用户在首次登录后,访问其他相关系统时无需再进行登录操作,实现了“一键式”访问多个系统。
- 快速切换:在不同应用间无缝切换,无需重复身份验证,提供流畅的跨系统工作或浏览体验。
安全管理强化:
- 集中身份验证:通过单一、安全的认证中心处理用户登录,可以实施更严格的身份验证策略,如多因素认证(MFA)、强密码策略等。
- 降低密码泄露风险:因为用户只需管理一个主密码,减少了因使用弱密码、复用密码或在多个地方记录密码而导致的安全隐患。
- 实时账户管理:管理员可以集中监控登录活动、及时发现并响应异常行为,如异常登录位置、频繁失败尝试等,快速禁用或更新有问题的账户。
运维效率提升:
- 简化账户管理:集中式的用户账户创建、更新、删除和权限分配,减少了IT部门的管理工作量,有利于保持数据一致性。
- 降低支持成本:由于用户遇到的登录问题通常集中在单一的认证中心,技术支持可以更高效地定位和解决问题,减少用户求助次数。
- 易于扩展和集成:随着企业引入新的应用和服务,SSO架构能够轻松适应变化,只需将新系统与现有身份提供者对接,无需在每个新系统中重新实现登录功能。
# sso的不足之处
尽管单点登录(SSO)带来了诸多便利和安全优势,但作为一种复杂的技术解决方案,它也存在一些潜在的不足和挑战。以下列举了几点SSO的不足之处:
依赖性与单点故障风险: SSO系统的核心是中央身份认证服务(Identity Provider, IdP),所有依赖SSO的服务提供商(Service Provider, SP)都需要与IdP保持通信。如果IdP出现故障、网络中断或遭受攻击导致服务不可用,那么所有依赖SSO的系统都将无法进行正常的用户身份验证,可能导致大面积服务中断。这种高度依赖性使SSO系统成为潜在的单点故障源。
集中式风险: SSO将所有用户的认证信息集中存储在IdP中,虽然方便了管理,但也意味着一旦IdP的安全防护措施被突破,攻击者可能获取到大量用户的敏感信息,包括但不限于用户名、密码(可能为哈希值)、访问令牌等。这种集中式存储加大了数据泄露的风险,对数据保护和隐私合规提出了更高的要求。
复杂的部署与集成: 实现SSO通常需要对现有的系统架构进行改造,与各种第三方应用进行深度集成。这可能涉及到定制开发、配置调整、协议适配等工作,尤其对于老旧系统或非标准接口的应用,集成难度和成本可能会较高。此外,维护SSO系统及其与其他系统的互操作性也需要持续的技术支持和专业知识。
身份生命周期管理难题: 虽然SSO简化了用户登录过程,但对于用户身份的生命周期管理(如创建、更新、删除账户,权限变更等)却可能变得更加复杂。特别是当企业组织结构变动、员工离职、角色调整等情况发生时,需要确保所有相关系统的身份信息同步更新,否则可能导致权限错配或未及时撤销访问权限的问题。
跨域认证与信任模型: 在跨组织或跨云环境的SSO场景中,需要建立和维护复杂的信任关系。确定哪些IdP和SP之间应当建立信任,如何管理和更新信任关系,以及如何处理信任链中某环节失效或撤销信任等问题,都对管理者的策略制定和执行能力提出了挑战。
用户感知与控制减弱: 用户在享受SSO带来的便利的同时,可能会对其登录行为和数据共享有较少的直接感知与控制。例如,用户可能不清楚自己的身份信息何时、如何被不同系统共享,或者在退出某个系统时,其他系统仍保持其登录状态,这可能引发用户对隐私和数据控制权的担忧。
应急退出机制的复杂性: 在紧急情况下(如设备丢失、账户被盗),用户可能希望立即注销所有依赖SSO的服务。然而,实现全局、即时的退出并非易事,需要设计和实施有效的会话管理、令牌撤销机制,并确保所有相关系统能够及时响应这些操作。
总的来说,SSO虽然极大地提升了用户体验和系统安全性,但也带来了对可靠性和安全性的更高要求、复杂的系统集成与管理任务,以及对用户隐私和控制权的关注。在实施SSO时,需要充分考虑这些挑战,并采取适当的措施来缓解潜在问题。