简体   繁体   English

你能发现我的身份验证协议中的漏洞吗?

[英]Can you spot a vulnerability in my authentication protocol?

Some time ago we needed a solution for Single Sign On authentication between multiple web services. 前段时间我们需要一个多个Web服务之间的单点登录身份验证解决方案。 At least at that time we considered OpenID protocol too complicated and we were not convinced about the Ruby on Rails plugins for it. 至少在那个时候我们认为OpenID协议过于复杂,我们不相信它的Ruby on Rails插件。 Therefore we designed a protocol of our own instead of implementing an OpenID provider and OpenID consumers. 因此,我们设计了自己的协议,而不是实现OpenID提供者和OpenID使用者。

I have two questions: 我有两个问题:

  1. Was it a bad thing not to create our own OpenID provider and setup our OpenID consumers accept only it? 不创建我们自己的OpenID提供商并设置我们的OpenID消费者只接受它是不是一件坏事吗? Public login or registration are not allowed and we wanted to keep authentication simple. 不允许公开登录或注册,我们希望简化身份验证。

  2. Can you spot a crucial error or a vulnerability in the following design? 您能否在以下设计中发现关键错误或漏洞?

If you as a commune can approve this design, I will consider extracting this code into a Ruby on Rails plugin. 如果你作为一个公社可以批准这个设计,我会考虑将这个代码提取到Ruby on Rails插件中。

Please look at the flowchart and sequence diagram . 请查看流程图和顺序图

Details: 细节:

Authentication Provider ("AP"): 身份验证提供程序(“AP”):

  • Central service which holds all data about the users. 中央服务,包含有关用户的所有数据。
  • Only one "AP" exists in this setup. 此设置中只存在一个“AP”。
  • It could be possible to have multiple "AP"s, but that should not be relevant in this context. 有可能有多个“AP”,但在这种情况下这不应该是相关的。
  • "AP" knows each "S" beforehand. “AP”事先知道每个“S”。

Authentication Client (Service "S"): 身份验证客户端(服务“S”):

  • There exists several internal and external web services. 存在多个内部和外部Web服务。
  • Each service knows "AP" and its public key beforehand. 每个服务事先都知道“AP”及其公钥。

Actor ("A"): 演员(“A”):

  • The end user who authenticates herself with AP by a username and password 通过用户名和密码使用AP对自己进行身份验证的最终用户
  • May request directly any URI of "S" or "AP" prior to her login 可以在登录前直接请求任何“S”或“AP”URI

Connections between "A", "S" and "AP" are secured by HTTPS. “A”,“S”和“AP”之间的连接由HTTPS保护。

Authentication logic described briefly: 简要描述了认证逻辑:

These are a description for the graphical flowchart and sequence diagram which were linked at the top of this post. 这些是对本文顶部链接的图形流程图和序列图的描述。

1) Auth Provider "AP" 1)Auth Provider“AP”

  • "AP" makes a server-to-server HTTP POST request to "S" to get a nonce. “AP”向“S”发出服务器到服务器HTTP POST请求以获取现时。
  • "AP" generates an authentication token. “AP”生成身份验证令牌。
  • Authentication token is an XML entity which includes: 身份验证令牌是一个XML实体,包括:
    • an expiration date (2 minutes from now), 到期日(从现在起2分钟),
    • the previously requested nonce (to prevent replay), 先前请求的随机数(以防止重播),
    • identifying name of "S" (token for Service_1 is not good for Service_2), 识别“S”的名称(Service_1的令牌不适合Service_2),
    • information about the end user. 有关最终用户的信息。
  • Authentication token is encrypted with AES256 and the encryption key and initialization vector are signed by AP's private RSA key. 身份验证令牌使用AES256加密,加密密钥和初始化向量由AP的私有RSA密钥签名。
  • Resulting strings ("data", "key" and "iv") are first Base64 encoded and then URL encoded to allow them be delivered in the URL query string. 产生的字符串(“data”,“key”和“iv”)首先进行Base64编码,然后进行URL编码,以允许它们在URL查询字符串中传递。
  • End user "A" is HTTP-redirected to service "S" (HTTPS GET request). 最终用户“A”被HTTP重定向到服务“S”(HTTPS GET请求)。

2) Service "S" 2)服务“S”

  • Receives authentication token in URL parameters from user agent. 从用户代理接收URL参数中的身份验证令牌。
  • Decrypts authentication token with AP's pre-shared public key. 使用AP的预共享公钥解密身份验证令牌。
  • Accepts one authentication token only once (token includes a nonce which is valid only once). 仅接受一次身份验证令牌(令牌包含仅一次有效的nonce)。
  • Checks that identifying name in authentication token corresponds to service's name. 检查身份验证令牌中的标识名称是否与服务名称相对应。
  • Checks that authentication token is not expired. 检查身份验证令牌是否已过期。

Remarks: 备注:

It is not a problem if somebody else can also decrypt the authentication token, because it contains no confidential information about the user. 如果其他人也可以解密身份验证令牌,这不是问题,因为它不包含有关用户的机密信息。 However, it is crucial that nobody else than AP is able to generate a valid authentication token. 但是,除AP之外的其他任何人都无法生成有效的身份验证令牌。 Therefore the RSA key pair is involved. 因此涉及RSA密钥对。

RSA private key is used only for signing the token, because it cannot encrypt data which is longer than the actual key length. RSA私钥仅用于对令牌进行签名,因为它无法加密比实际密钥长度更长的数据。 Therefore AES is used for encryption. 因此,AES用于加密。

Since the authentication token is delivered as an HTTP GET request, it will be stored eg in Apache's log file. 由于身份验证令牌是作为HTTP GET请求传递的,因此它将存储在例如Apache的日志文件中。 Using a disposable nonce and an expiration date should minimize the possibility of a replay attack. 使用一次性随机数和失效日期应尽量减少重放攻击的可能性。 POST request would need an HTML page with a form which is submitted automatically by Javascript, which is why GET is used. POST请求需要一个HTML页面,其中包含由Javascript自动提交的表单,这就是使用GET的原因。

Service "S" generates a nonce only in a server-to-server API request. 服务“S”仅在服务器到服务器API请求中生成随机数。 Therefore unauthenticated generation requests should not pose a DoS-vulnerability. 因此,未经身份验证的生成请求不应构成DoS漏洞。

You're confusing authentication ("I am who I say I am") and authorization/access control ("I am allowed to access this"). 您会混淆身份验证(“我就是我说的是我”)和授权/访问控制(“我可以访问它”)。 You can just implement OAuth, and then query a server over HTTPS with "is this OAuth identity allowed to access me?". 您只需实施OAuth,然后通过HTTPS查询服务器“是否允许此OAuth身份访问我?”。 You don't have to worry about replay attacks, since you're using HTTPS. 您不必担心重放攻击,因为您使用的是HTTPS。

"Security is hard, so I'll design my own." “安全很难,所以我会自己设计。”

Authentication token is encrypted with AES256 and the encryption key and initialization vector are signed by AP's private RSA key. 身份验证令牌使用AES256加密,加密密钥和初始化向量由AP的私有RSA密钥签名。

AES-256 and AES-192 have weak key schedules. AES-256和AES-192具有弱密钥时间表。 But you're not using it for confidentiality; 但你不是用它来保密; you're using it as some sort of "integrity" check. 你正在使用它作为某种“完整性”检查。 It doesn't work: Attacker gets a "signed" authentication token. 它不起作用:攻击者获得“签名”身份验证令牌。 Attacker recovers the key and IV. 攻击者恢复了密钥和IV。 Attacker encrypts a different authentication token with the same key and IV, and uses the same "signature". 攻击者使用相同的密钥和IV加密不同的身份验证令牌,并使用相同的“签名”。

What's wrong with hashing it and signing the hash? 散列它并签署哈希有什么问题? Also note that if you're going to use custom signing, you need to be careful about padding (IIRC PKCS-whatever adds at least 11 bytes). 另请注意,如果您要使用自定义签名,则需要注意填充(IIRC PKCS-无论添加至少11个字节)。

EDIT: And if you're using a cipher where you should be using a hash/MAC, you really shouldn't be designing a security protocol! 编辑:如果您使用的密码应该使用散列/ MAC,那么您真的不应该设计安全协议!

Here are a few quick thoughts about question 1: 以下是关于问题1的一些快速思考:

  • Designing a working security protocol is very hard, so on general principle I would favor using an existing one. 设计一个有效的安全协议是非常困难的,所以基于一般原则,我倾向于使用现有协议。

  • However, I appreciate that OpenID might not have been very established at the time. 但是,我很欣赏OpenID当时可能还不是很成熟。 Also OpenID is still relatively new and might not have all of its limitations figured out yet. 此外,OpenID仍然相对较新,可能尚未解决所有限制。

  • Still, you'd be using OpenID in a restricted scenario where the big issue of OpenID (involvement of multiple actors) doesn't come into play. 尽管如此,你仍然在一个受限制的情况下使用OpenID,其中OpenID的大问题(多个参与者的参与)没有发挥作用。 You'd only be using the “technical core” of OpenID, which is easier to understand. 您只使用OpenID的“技术核心”,这更容易理解。

  • Your requirements and the overview of your protocol remind me of Kerberos. 您的要求和协议概述让我想起了Kerberos。 I'm also tempted to push towards LDAP + single sign on, but I don't know what concrete solutions exist for that. 我也很想推动LDAP +单点登录,但我不知道具体的解决方案是什么。

  • A point in favor of your protocol is that you've taken the time to describe it in detail. 赞成你的协议的一点是你花时间详细描述它。 Just that puts you above than most self-made security protocol designers! 只是这使你超过大多数自制的安全协议设计师!

In short I find this protocol to be over engineered in the wrong places and ultimately vulnerable to attack. 简而言之,我发现这个协议在错误的地方过度设计,最终容易受到攻击。

So What is the vulnerability? 那么什么是漏洞?

End user "A" is HTTP-redirected to service "S" (HTTPS GET request). 最终用户“A”被HTTP重定向到服务“S”(HTTPS GET请求)。

This is likely to be a violation of OWASP A9 . 这很可能违反了OWASP A9 At no point can a user's session ID be passed over an insecure channel such as http. 用户的会话ID在任何情况下都不能通过不安全的通道(例如http)传递。 Even if the session id hasn't been authenticated yet, an attacker is patient he can sniff the wire looking for session id's and then periodically check if they have been authenticated and then use them to access your system. 即使会话ID尚未经过身份验证,攻击者仍然有耐心,他可以嗅探线路查找会话ID,然后定期检查它们是否已经过身份验证,然后使用它们访问您的系统。

"Complexity is the worst enemy of security." “复杂性是安全的最大敌人。”

--Bruce Schneier - 布鲁斯施奈尔

Authentication token is encrypted with AES256 and the encryption key and initialization vector are signed by AP's private RSA key. 身份验证令牌使用AES256加密,加密密钥和初始化向量由AP的私有RSA密钥签名。

First of all RSA can be used to encrypt a message, so aes is unnecessary. 首先,RSA可用于加密消息,因此不需要。 HTTPS on the other hand is going to be more efficient and proven to be secure. 另一方面,HTTPS将更有效并且被证明是安全的。 I don't understand why you have to pass an authentication token to the client, when you already have a secure server-to-server communication channel. 当您已经拥有安全的服务器到服务器通信通道时,我不明白为什么必须将身份验证令牌传递给客户端。 A server could just say "Hey someone has been redirected to me with this session id, what is his state information?". 服务器可以说“嘿,有人被重定向到这个会话ID,他的状态信息是什么?”。 Its a matter of the weakest link in the chain, and your session id should be strong enough. 这是链条中最薄弱的环节,你的会话ID应该足够强大。 This would require the session id to be sent as a GET or POST request by the client when the hand off occures which could open the door to Session Fixation . 这将要求客户端在发生切换时发送会话ID作为GET或POST请求,这可能会打开Session Fixation的大门。 You could check the ip address before and after the handoff, sometimes the ip address of the client can change legitimately but the handoff is going to be a very narrow window in which this can happen, and most importantly it is stops Session Fixation altogether. 您可以在切换之前和之后检查IP地址,有时客户端的IP地址可以合法地改变,但是切换将是一个非常狭窄的窗口,在这种情况下可以发生这种情况,最重要的是它会完全停止会话固定。

In general you should avoid re-inventing the wheal. 一般来说,你应该避免重新发明风团。 Especially when it comes to security problems like this which have already been solved. 特别是当涉及到这样已经解决的安全问题时。 Kerberos is beautiful especially if you need to tie in non-http authentication. 如果您需要绑定非http身份验证,Kerberos非常漂亮。 Using LDAP for session management is another possibility. 使用LDAP进行会话管理是另一种可能性。

Do you really just sign AES key and then send encrypted token, RSA signature of key and then key-iv in PLAINTEXT? 你真的只是签署AES密钥,然后发送加密令牌,密钥的RSA签名,然后在PLAINTEXT中发送key-iv?

It's a fail. 这是一个失败。 Attacker can use this key to decrypt a token, change it in any needed way and encrypt back. 攻击者可以使用此密钥解密令牌,以任何需要的方式更改它并加密回来。 Your server will never find a difference. 您的服务器永远不会发现差异。

If you want to check token integrity, just make a hash of it and sign this hash. 如果要检查令牌完整性,只需对其进行哈希并对此哈希进行签名即可。 This is what hashes used for. 这就是哈希所用的。 No need to use encryption here. 这里不需要使用加密。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM