需要将脱机和Touch ID添加到Microsoft身份验证层 [英] Need to add Offline and Touch ID to Microsoft Authentication Layer

查看:92
本文介绍了需要将脱机和Touch ID添加到Microsoft身份验证层的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些Xamarin C#代码可以根据公司目录对用户进行身份验证,基本上是在 Microsoft教程,现在我们仅支持iOS:

I have some Xamarin C# code that authenticates users against the company directory, it's basically the code found in the Microsoft tutorial, and right now we're iOS-only:

App.xaml.cs

PublicClientApplicationOptions options = new PublicClientApplicationOptions()
{
    ClientId = MyAppClientId,
    TenantId = MyAppTenantId
};
var builder = PublicClientApplicationBuilder.CreateWithApplicationOptions(options);
if (!string.IsNullOrEmpty(iOSKeychainSecurityGroup))
{
    builder = builder.WithIosKeychainSecurityGroup(iOSKeychainSecurityGroup);
}
PCA = builder.Build();

ViewModel.cs

string Scopes = "User.Read";
var scopes = Scopes.Split(' ');  // Yeah, overkill

// First, attempt silent sign in
// If the user's information is already in the app's cache,
// they won't have to sign in again.
string accessToken = string.Empty;
try
{
    var accounts = await App.PCA.GetAccountsAsync();
    // PCA.GetAccountsAsync() returned [List<IAccount> #=0]
    if (accounts.Count() > 0)
    {
       var silentAuthResult = await App.PCA
          .AcquireTokenSilent(scopes, accounts.FirstOrDefault())
          .ExecuteAsync();
       accessToken = silentAuthResult.AccessToken;
    }
 }
 catch (MsalUiRequiredException)
 {
    // This exception is thrown when an interactive sign-in is required.
    // Don't need to do anything, we will notice the empty access token later
 }

 if (string.IsNullOrEmpty(accessToken))
 {
     // Prompt the user to sign-in
     var interactiveRequest = App.PCA.AcquireTokenInteractive(scopes);
     // PCA.AcquireTokenInteractive(scopes) returned Microsoft.Identity.Client.AcquireTokenInteractiveParameterBuilder
     if (authUiParent != null)
     {
        interactiveRequest = interactiveRequest
           .WithParentActivityOrWindow(authUiParent);
     }

     try
     {
        var authResult = await interactiveRequest.ExecuteAsync();
     }
     catch (MsalClientException clientException)
     {
        // When I entered the wrong password, and then hit cancel:
        // Or, when I got the "you need admin permissions" error and then hit cancel:
        /*
        interactiveRequest.ExecuteAsync() threw MsalClientException [error code "authentication_canceled"]
        Exception MsalClientException: User canceled authentication.
        */
     }
  }

效果很好,现在我需要稍有不同(当然).

That's working great, now I need it to be slightly different (of course).

1)首先,我们需要离线"模式.如果用户要在没有Internet的地方访问应用程序,我们希望他们输入其用户名和密码,并将其与该用户的最新已知有效值进行比较.现在,我们正在使用内部加密数据库来存储最后一个已知的好值以进行比较.是的,这里有一个安全漏洞,如果我们在服务器上禁用了用户帐户,只要他们在移动设备上禁用了互联网,他们就可以继续登录-我们还有其他方法可以最大程度地减少这一问题,而我不会不要进入这里.

1) First of all, we need an "offline" mode. If the user wants to access the app in a place that has no Internet, we want them to enter their username and password which will be compared against the last known good value for that user. Right now we are using an internal encrypted database to store last known good values for comparison. Yes, there is a security hole here, if we've disabled a user's account on the server they can continue to log in as long as they disable the Internet on their mobile device - we have other ways to minimize this problem that I won't go into here.

2)其次,我们要允许触摸ID.但是,即使指纹验证了用户的身份,我们仍然要检查该用户是否已在服务器上被禁用-因此我们需要将该用户的最后已知正确值"发送到服务器以进行验证.当然,如果没有互联网,指纹就足够了.我假设这意味着在调用AcquireTokenInteractive()之前需要一个屏幕,在该屏幕上我们为用户提供了使用Touch ID的机会,并带有一个按钮,显示不,我想输入我的用户名和密码"

2) Secondly, we want to allow touch ID. But even if the fingerprint verifies the identify of the user, we still want to check if that user has been disabled at the server - so we need to send the "last known good values" for that user to the server for verification. Of course, if there is no Internet, the fingerprint will be enough. I'm assuming this means we need a screen before calling AcquireTokenInteractive() where we give the user a chance to use Touch ID, with a button that says "nope, I want to type in my username and password please"

3)最后,即使我们拥有Internet且用户选择不使用Touch ID,我们也希望他们每次都输入密码.我们想记住最近登录用户的用户名,并填写该用户名以加快操作速度,但是出于安全原因,我们每次都需要输入密码.

3) Finally, even when we have Internet and the user has chosen to not use Touch ID, we want them to enter their password every time. We want to remember the username of the most-recently-logged-in user and fill that in for them to speed things up, but for security reasons we need a password every time.

推荐答案

您的应用程序的安全性似乎是您最大的担忧.因此,我将详细介绍安全性和身份,以帮助您做出决策.

It seems security of your application is your biggest concern. For this reason I'll go in to some detail on security and identity to help your decision making.

恐怕您不建议采用离线访问方法.实际上,在MSAL中,我们通过使用系统浏览器来积极地缓解这种情况.

I'm afraid the approach you've taken for offline access isn't advisable. In fact, in MSAL we actively mitigate it by using the System Browser.

当用户使用嵌入式Web视图或基于表单的身份验证登录到移动应用程序时,该应用程序可以访问输入到该应用程序中的纯文本用户名和密码.如果用户从您的公司下载行为类似于合法应用程序的应用程序,则这些凭据可能会在用户不知情的情况下被盗.这是一个安全漏洞,严重程度足以使Google采取

When a user signs in to a mobile application using either an embedded webview or a form based authentication, that application can access the plain text username and password entered in to the application. If a user downloads an application that is acting like a legitimate application from your company, those credentials can be stolen without the user being aware. This is a security vulnerability, and one that is severe enough that Google has taken the step of blocking all apps that use embedded webview or forms based authentication.

为防止应用程序对凭据的这种存储,Google,Microsoft和其他公司已切换到系统浏览器以收集凭据.我们使用移动设备上操作系统的新功能来在您的应用程序之上显示Web登录体验.这似乎是用户的本机,但实际上是操作系统的浏览器.因为应用程序和Microsoft都无法访问操作系统的浏览器,所以用户输入的凭据是安全的.您将看到使用此模式的大多数现代应用程序.

To prevent this storage of credentials by applications Google, Microsoft, and others have switched to the System Browser to collect credentials. We use the new ability of the operating system on mobile devices to display a web sign-in experience on top of your application. This appears native to the user but is actually the browser of the operating system. Because neither the application nor Microsoft has access to the browser of the operating system, the credentials entered by your users are safe. You'll see most modern applications using this pattern.

这也将阻止您存储用户名和密码,这是设计使然.请不要将用户的凭据存储在任何地方.

This will also prevent you from storing username and password of your users and is by design. Please don't store your user's credentials anywhere.

为了正确实现您的方案,我们已经看到了应用程序使用的两个选项:

To achieve your scenario correctly there are two options we've seen apps use:

  • 我们看到的最流行的模式是应用程序要求用户在首次登录时或在设置"中作为选项来设置PIN来访问应用程序.如果Touch ID/Face ID失败或被重置,通常会要求用户设置PIN以及Touch ID/Face ID.然后,用户在每次启动时使用PIN来访问该应用程序,并且在不可用互联网时也可以使用.此PIN码已安全存储并在设备上加密.互联网可用后,应用程序应调用acquireTokenSilently()以确保用户仍然可以访问资源.如果没有,则应提示用户再次登录.许多银行和其他受到严格监管的行业都将这种模式用作用户体验和安全性之间的最佳折衷.

  • The most popular pattern we've seen is for applications to ask the user to set a PIN to access the application when they first sign-in or as an option in Settings. Often times the user is asked to set a PIN as well as Touch ID/Face ID if Touch ID/Face ID fails or is reset. The user then uses the PIN to access the app on each launch, and this also works when internet isn't available. This PIN is stored securely and encrypted on the device. As soon as the internet is available the application should call acquireTokenSilently() to ensure the user still has access to the resource. If they don't, you should prompt the user to sign in again. Many banks and other highly regulated industries use this pattern as the best compromise between user experience and security.

下一个选择是对希望用户在发生故障时保持对资源的访问的公司和应用程序开发人员,使用我们在库中内置的弹性.我们允许公司和应用程序开发人员配置令牌生存期,该生存期比访问令牌和刷新令牌的默认令牌生存期长.当用户无法访问Internet以获得新的访问令牌时,延长的生存期可以使用户继续使用该应用程序.

The next option is to use the resiliency we've built in to the library for companies and application developers that want the user to maintain access to resources in case of an outage. We allow companies and application developers to configure a token lifetime that is longer than our default token lifetime for access tokens and refresh tokens. When a user isn't able to access the internet to get a new access token, the extended lifetime can allow the user to continue to use the application.

如果您的API在您的环境中是本地的,但是身份提供者是基于云的,或者如果Azure AD发生故障而Internet的其余部分仍在工作,则这具有工作的额外好处.您的内部API将接受令牌,因此即使无法访问Internet,您的用户也可以继续工作. API和您的应用程序都将需要使用MSAL,以使您的API遵守令牌中指定的延长的生存期.请记住,我们拥有一天的访问令牌的最大价值.如果您的互联网中断时间长于此时间,我建议使用上面的选项1.

This has the added benefit of working if your APIs are local to your environment but the identity provider is cloud based or if Azure AD is suffering an outage but the rest of the internet is working. Your internal APIs will accept the tokens so your users can continue to work even if the internet is inaccessible. Both the API and your app will need to use MSAL in order for your API to honor the extended lifetime specified in the token. Keep in mind we have maximum value for the access token of one day. If your internet outage is longer than that, I recommend using option 1 above.

这个答案很简单.使用Touch ID后,只需使用acquireTokenSilently().这将为您请求令牌的资源获取一个新令牌.对于默认令牌值,访问令牌将每1小时刷新一次.我不建议强行对每个Touch ID进行身份验证,因为这会导致速度显着降低和移动电话使用率提高.如果您只想检查用户的存在,我建议您使用上面讨论的本地存储的PIN.

This answer is fairly easy. Just use acquireTokenSilently() after the Touch ID is used. This will acquire a new token for the resource you requested the token for. For default token values, the access token will be refreshed every 1 hour. I do not recommend forcing authenticating every Touch ID as that will introduce significant slowdown and cellular usage. If you just want to check the user is present, I recommend you use a locally stored PIN as discussed above.

您可以随时通过使用带有适当值的acquireToken()来强制进行身份验证.有关方法AcquisitionTokenInteractively().

You can force authentication at any time by using acquireToken()with the appropriate values. See the code sample here for the method acquireTokenInteractively().

但是,这里有一些关于可用性的警告:

However, a small amount of warning here on usability:

身份服务用于检查用户是否有权访问资源,而不是检查用户是否有权访问设备或该用户是否仍是上一个会话中的用户.为此,您应该使用上面讨论的PIN方法以及Touch ID/Face ID(如果可用).为什么?

The identity service is used to check if a user has access to the resources, not to check if the user has access to the device or if the user is still the user from a previous session. For that you should use the PIN method I discuss above, along with Touch ID/Face ID if available. Why?

为了真正的安全,密码应与2FA结合使用.研究表明

For true security, a password should be combined with 2FA. Research indicates that 99% of illegal access can be mitigated by 2FA. However, when a user has to use 2FA for a sign-in it increases the friction they have to do endure to sign-in. In fact, relying on passwords at all is problematic.

您的用例似乎表明您想要您的应用程序的最大安全性.如有可能,必须使用2FA.但是,要使应用程序达到最佳安全状态,也会使用户每次启动应用程序时都很难使用密码.

Your use case seems to indicate you want the maximum amount of security for your application. That necessitates using 2FA if possible. However, moving to the best security posture for your application would also make using a password at every app launch very difficult for your users.

在更改用户对资源的访问权限后或很长一段时间后,建议的模式还是PIN或Touch ID/Face ID以及密码提示.

The recommended pattern would again be PIN or Touch ID/Face ID along with a password prompt after either a change to the user's access to a resource or after a long period of time.

这篇关于需要将脱机和Touch ID添加到Microsoft身份验证层的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆