首先最重要的是:如果您想要安全,请不要使用 MIFARE 卡。他们在安全方面不是最好的。即使卡片不易受到强化攻击或蛮力攻击之类的攻击,卡片的数据仍然可以通过无线方式被嗅探(其中包括密钥或允许密钥和数据轻松恢复)。
通常,大多数“安全”的 MIFARE 卡将利用多个系统来检测卡的真实性。考虑一个两阶段的方法:
首先,利用内置的扇区键。扇区密钥虽然有 6 个字节大小,但由于卡的工作原理,很难破解。没有办法“转储 MIFARE 密钥块的哈希”,因此您基本上需要通过无线/卡上的方式进行破解。由于您不仅限于 ASCII,因此攻击者仍然仅限于通过单个密钥的 281.4 万亿个可能的位组合的最坏情况。
二是利用卡片状态验证。有很多方法可以做到这一点,但一个常见的解决方案是使用价值块系统来跟踪卡的使用次数。下面有一个示例过程。
像这样的两阶段方法可以让您将那些只是试图将他们的卡克隆到他们的手机而没有任何经验的临时用户拒之门外。它还允许您(在某种程度上)对读者自己执行身份验证,这总比没有好。如果在攻击者不知道系统如何工作的情况下复制/破坏一张卡片,则复制的卡片只能在两张卡片与您的服务器失去同步之前使用一次,并冒其中一张卡片导致两者都被停用的风险。
正如您所提到的,加密卡数据之类的解决方案实际上并不能阻止攻击者,只会让他们更难读取卡上的数据。如果密钥不存在,则 MIFARE 块甚至不可读,因此加密确实成为不必要的第二步,除非您试图保护秘密。
在这个示例系统中,您拥有三个组件:阅读器、后端身份验证服务器和卡。在卡上,扇区 1 和 2 由应用程序的数据使用:
- 扇区 1包含分配给卡的唯一序列号。此序列号受密钥 B 中的全局静态密钥保护。卡设置权限模式
101
为只允许从密钥 B 读取。不需要设置密钥 A。
- 扇区 2有点复杂,因为它包含两个块。密钥 B 应为每张卡随机生成,密钥 A 可以忽略。
- 块 0包含在创建时分配给卡的随机生成的秘密值。此块的权限设置
101
与扇区 1 中使用的权限类似。
- Block 1利用 MIFARE 卡的 Value Block 功能来跟踪卡的使用次数。在这种情况下,值块被初始化为 value
2,147,483,647
(有符号 32 位数字的最大值)。该块的权限设置为001
可以使用密钥 B 来减少此计数器。
每次卡片签入时,都会发生以下过程:
- 读卡器使用扇区 1 的静态密钥 B 来获取卡的唯一序列号。
- 读卡器从授权服务器请求卡片元数据,授权服务器响应:
- 当前卡的期望值
- 该读卡器是否可以刷卡(该用户是否授权)
- 此卡的(随机)密钥 B
- 此卡在 Sector 2 Block 0 中的秘密值
- 读卡器读取扇区 2 并检查卡的秘密值和当前计数器。
- 如果其中一个值是错误的,则卡的值块将递减到零以下,从而使卡变砖。
- 如果两个值都正确,则卡的值块减一并授予卡访问权限。
- 阅读器将卡片的新期望值发送给服务器。如果卡被“变砖”,它将被标记为禁用并生成安全警报。
如果需要额外的安全性(例如,读卡器不可信),读卡器可以将卡的值发送回服务器进行授权。请注意,这确实会增加一些(通常是微不足道的)延迟,但根据应用程序可能会很烦人。
另请注意,这样的示例系统高度依赖于始终在线的所有内容。如果无法访问服务器,您可能希望系统故障“安全”并在某些情况下授予访问权限。如果要这样做,读者应该缓存读取事件,然后在服务器重新联机后提交它们。这将需要对卡片验证系统进行一些重组,以确保所有读取都是“可信的”,并且通常需要作为计划工作或类似概念进行。
任何这样的系统都是(非常)可变的,实际的实现细节取决于您希望这样的系统在每个边缘情况下的安全性和可用性。请记住,在某个时间点之后,您对安全性的投资回报开始下降,额外的复杂性变成了复杂性的复杂性。