介绍
Pinterest 已强制在我们的 Okta 身份验证流程中使用托管和合规设备,使用无密码实施,因此访问我们的工具始终需要健康的 Pinterest 设备。
在针对科技行业同行的基于网络钓鱼的攻击之后,Pinterest 决定采取双管齐下的方法来抵御类似攻击。我们决定:
- 要求使用受管理且健康的 Pinterest 设备访问所有 Pinterest 资源,即使拥有有效凭据也是如此
- 需要 FIDO2 凭据进行用户身份验证
在这篇文章中,我们将重点关注我们如何要求在我们的 Okta 身份验证流程中使用 Pinterest 托管设备。
图 1:Android 设备上的用户无法进行身份验证。
图 2:macOS 上的用户收到有关某些合规性失败的警告。
为什么选择设备 AuthN 和合规性
这一举措背后有一些驱动力:
- 随着PinFlex WFH政策的推出,我们预计会有更多员工在办公室外与 Pinterest 工具和服务进行交互。
- 对于面向员工的工具,Pinterest 是一家以 SaaS 为先的公司,这意味着我们的绝大多数工具都可以通过互联网访问。这些工具将仍然可以通过互联网访问,要么是出于选择,要么是因为缺乏基于 IP 的本机白名单功能。
- 我们对以网络为中心的安全控制的兴趣已经减弱。虽然这并不意味着 VPN 或基于内部网络的访问将完全消失,但我们认识到我们的默认立场不会强制用户在特定网络上访问资源,尤其是 SaaS工具。
- 我们有一组重要的安全控制,这些控制仅存在于公司管理的设备和/或带有 MDM 的移动 BYOD 上。
我们认为,通过确保以下几点,要求使用受管理且健康的设备进行身份验证可以减轻上述一些丢失的安全边界:
- 仿冒的用户凭据(无论是密码、OTP 还是推送通知)不会导致对 Pinterest 资源的访问。
- 无法从非托管或未知设备访问可访问 Internet 的 Pinterest 工具,包括那些可能包含敏感数据的工具。
- 托管设备将处于加固状态,使对手更难立足。
与 Okta 集成
在研究 Okta 中的不同集成选项时,Okta Classic 客户发现了一些显而易见的事情:
- MDM 提供商和 Okta 之间确实存在的现有定制设备相关集成,例如 Device Trust with Jamf 或 WS1,并没有为客户提供全面的解决方案。
- 如果 Okta 客户或潜在供应商想要与 Okta 集成以通过身份验证流程做一些“有趣”的事情,那么这样做的唯一途径是与某些外部身份提供者 (idP)建立互信,那些“有趣”的事情可以发生。
因此,我们别无选择,只能构建用户并将其路由到我们自己的自定义身份提供程序。Zuul(向Netflix 致歉)是 Pinterest 安全团队构建的 OIDC 身份提供程序,目的是将我们的设备身份验证和合规性要求纳入 Okta 身份验证流程。
图 3:使用 idP 路由/发现的 Okta 身份验证的高级流程图
与该领域的一些供应商一样,我们使用 IdP 路由/发现将我们的 IdP 与 Okta 集成,其中我们的 IdP 充当受信任的外部身份提供者。我们使用“IdP 作为 SSO”方法而不是“IdP 作为因素/MFA”方法与 Okta 集成,因为后者与我们的 FIDO2 实施相冲突。
就其核心而言,从 Okta 的角度来看,我们的 IdP 只不过是一个合规的 OIDC IdP。但是,现在我们处于 SSO 身份验证的关键路径,可以增强整个体验以及身份验证请求的成功,以强制使用托管和合规设备。
双向 TLS 认证
任何基于设备的解决方案都需要克服的挑战之一是能够将身份验证尝试与特定设备相关联。这个要求就是为什么基于证书的方法是一个有吸引力的选择。
我们通过我们的 MDM 解决方案向所有托管设备(包括桌面和移动平台)颁发证书,这需要用户进行身份验证才能向设备颁发证书。这使我们能够:
- 通过在 MDM 注册期间在颁发给设备的 PKI 证书中编码用户身份,在与他们交互之前确定用户身份(例如 FIDO2)
- 将身份验证尝试与物理设备相关联,因为证书是在注册期间颁发给该设备的
- 避免特定于平台的代理,因为我们在 Pinterest 支持的平台本身支持基于证书的身份验证,因此我们能够利用与平台无关的身份验证方法
我们的自定义 IdP 仅支持使用客户端证书进行 mTLS 身份验证,使用绑定到用户和设备的证书。如果没有仅分发给托管设备的有效客户端证书,则无法对我们的 IdP 进行身份验证。
对于不支持相互 TLS 身份验证的应用程序,出于后续博客文章中所述的原因,存在一种变通方法可以恢复为基于密码的身份验证。
外部 IdP 解决方案的问题
另一个需要克服的障碍是 Okta 缺乏对外部身份提供者的“执行”。尽管我们可以将用户路由到外部身份提供者,但 Okta 不提供正确强制使用身份提供者所需的工具。
Okta明确指出使用 IdP 路由和相应的 IdP 路由规则不是安全控制:
路由规则改善了最终用户的登录体验,但它们不提供安全增强功能。您需要独立于您的路由规则为您的 IdP 配置用户身份验证策略。
这实际上意味着我们不能将外部 IdP 视为一种“可选”形式的身份验证。在不采取任何额外步骤来强制使用外部 IdP 的情况下,通过恢复到 Okta 基于用户名/密码的身份验证来绕过外部 IdP 的使用是微不足道的。
在上面的引用中,Okta 暗示将“用户身份验证策略”作为一种强制执行方法。如果这些引用的策略是实际的“应用程序登录策略”,那么执行就不是问题了。不幸的是,唯一存在的 Okta 策略是“全局登录”策略,它无法解决您可能会遇到的不可避免的应用程序异常,因此不实用。
SAML 内联挂钩——“自定义”应用程序登录策略
SAML 内联挂钩允许外部服务在 SAML 断言由 Okta 签名之前修改 SAML 断言。从表面上看,这与设备身份验证解决方案并没有真正相关,但有一种值得注意的返回类型引起了我们的兴趣:通过返回错误来拒绝访问尝试的能力。
Okta 在 SAML Inline Hook 中发送的请求包含一些有关应用程序访问尝试的相关信息,包括:
- 正在访问的应用程序
- 试图访问应用程序的用户
- 用户的 Okta 会话是如何建立的
在下面的示例中,请注意这两个应用程序访问尝试中的“会话”之间的区别。
拒绝访问尝试(未使用外部 IdP)
{
"context":
{
"protocol":
{
"issuer":
{
"id": "app_id",
"name": "application_name",
"uri": "http://www.okta.com/<app_id>"
}
},
"session":
{
"idp":
{
"id": "okta_idp_id",
"type": "OKTA"
}
}
}
}
允许访问尝试(使用外部 IdP)
{
"context":
{
"protocol":
{
"issuer":
{
"id": "app_id",
"name": "application_name",
"uri": "http://www.okta.com/<app_id>"
}
},
"session":
{
"idp":
{
"id": "zuul_idp_id",
"type": "SOCIAL"
}
}
}
}
这意味着我们可以以编程方式为每个应用程序访问尝试做出基于访问的决定。对于应该继续的访问尝试,我们返回一个空响应。对于需要拒绝的访问尝试,我们抛出一个错误。换句话说,我们可以通过使用内联挂钩固定我们自己的自定义应用程序登录策略来克服 Okta 应用程序登录策略中存在的任何限制。
为了改善用户体验,我们还会在出现此错误时撤销用户的 Okta 会话。
在下面的示例中,用户已经建立了一个 Okta 会话,其中一种方法可以绕过 IdP 路由,试图绕过我们的设备要求。然而,他们仍然无法访问需要我们的外部 IdP 的应用程序。
图 4:由于未使用正确的 idP 建立 Okta 会话,SAML Inline Hook 阻止了应用程序访问尝试
尽管 SAML Inline Hooks 对我们来说是一个很好的临时解决方案,但这绝不是理想的。SAML 内联挂钩必须在每个应用程序的基础上启用,并且只能在 Okta 中手动配置的应用程序上启用,因此可能需要对应用程序进行一些重新配置。我们计划重新配置从Okta 集成网络下载的应用程序,其唯一目的是在这些应用程序上启用我们的 SAML 内联挂钩。
我们希望 Okta 能在 Okta Classic 或 OIE 中发布一些东西,允许我们在每个应用程序的基础上本地执行 IdP,配置也允许 FIDO2 执行。或者,可以普遍应用于每个 Okta 应用程序的用于一般身份验证的“Inline Hook”也是一个有趣的选择。
设备合规性
既然每次 Okta 身份验证尝试都需要用户针对我们的 IdP 进行身份验证,我们就有机会评估设备的健康状况。我们合规政策的目的是执行我们的安全强化指南,以确保能够访问我们工具的设备群符合规定并处于强化状态。
如果合规性失败的设备尝试进行身份验证,我们可以采取一些措施,包括向用户发出警告,或者根据某些策略,完全阻止身份验证尝试。
图 5:macOS 上的用户收到有关某些合规性失败的警告。
我们的合规框架允许一些对我们很重要但在其他解决方案中不常见的功能。这包括:
- 定义为代码的策略,允许我们在必要时创建复杂的策略
- 可以根据需要考虑来自尽可能多的数据源的数据的策略。我们目前与 Splunk、Chef、Workspace One 和 osquery 集成,并计划进行更多集成。
- 在策略失败时执行的“操作”,我们在这篇博文中展示了其中两个(阻止/警告)
- 使用我们现有的用于部署实验的生产框架,在整个队列中缓慢分片新策略的能力
下面我们创建了一个示例策略,以确保向 Okta 进行身份验证的用户是从他们拥有的设备上执行此操作并使用匹配的用户名登录该设备。
图 6:macOS 上的用户无法通过身份验证,因为他们的设备未通过示例策略“username_misma
下面是与此示例策略关联的代码。为了执行此评估,我们获取从两个不同数据源(Airwatch MDM 和 osquery)收集的数据,并将用户名与尝试向 Okta 进行身份验证的人进行比较。
@device_policy(
name="username_mismatch",
decider="zuul_device_policy_username_mismatch",
actions=[PolicyAction.BLOCK],
users=["atashjian"],
devices=[PolicyScope.ALL_DEVICES],
user_exception=[],
device_exception=[],
sources=[DataSource.OSQUERY, DataSource.AIRWATCH],
staleness_threshold=2400,
platforms=[DevicePlatform.MACOS],
remediation_message="The user attempting to auth, the local username on the device, "
"and the device owner, must all match."
)
def username_mismatch(device):
'''ensure that the user that's authenticating, the user logged in on the device, and the device owner match.
'''
authenticating_user = device.username
device_logged_in_user = device.collected_data[DataSource.OSQUERY].data['results']['data']['logged_in_user']['username']
airwatch_device_owner = device.collected_data[DataSource.AIRWATCH].data['UserName']
if authenticating_user == device_logged_in_user == airwatch_device_owner:
return PolicyResult(result=PolicyEval.PASS)
else:
return PolicyResult(result=PolicyEval.FAIL,
details=f"User Authenticating: {authenticating_user}, "
f"Device Owner: {airwatch_device_owner}, "
f"Logged In User: {device_logged_in_user}")
- 补丁状态
- 恶意软件检测
- 安全代理健康
- 日志摄取健康
- 应用程序/浏览器扩展
- 内核/系统扩展
- 根 CA
- CIS 强化指南
- 还有很多其他的东西!
结论
我们才刚刚开始我们的设备合规之旅,还有很多工作要做,包括:
- 不断编纂设备合规政策
- 额外的集成,用于收集数据以及在发生故障时执行操作
- 不仅在身份验证时,而且在持续的基础上评估设备合规性
- 通过在所有应用程序中启用 SAML 内联挂钩来弥补 Okta 执行方面的差距
作者:Armen Tashjian | Security Engineer, Corporate Security
出处:https://medium.com/pinterest-engineering/enforcing-device-authn-compliance-at-pinterest-a74938cb089b
创业项目群,学习操作 18个小项目,添加 微信:923199819 备注:小项目!
如若转载,请注明出处:https://www.zodoho.com/107854.html
