c# - samples - xamarin forms webview xaml
Xamarin Forms https con certificados de cliente lanza WebException (3)
En su manejador de excepciones, parece que no está llamando a Response.End ():
catch (Exception ex)
{
if (!(ex is System.Threading.ThreadAbortException))
Response.Write(ex.ToString());
}
Entonces, si se lanza una excepción del lado del servidor, es posible que la respuesta nunca se envíe al cliente. Recomendaría agregar un registro del lado del servidor de la excepción y ver si se proporciona algo útil de esa manera.
También parece que verifica ciertos campos del certificado del cliente, pero, por lo que puedo decir, no verifica que el certificado del cliente esté firmado por una raíz de confianza. Debe asegurarse de que ese sea el caso, o cualquiera puede generar un certificado autofirmado que contenga el nombre de usuario que desea suplantar y usarlo para engañar a su código, lo que sería una vulnerabilidad de seguridad grave.
Intento usar certificados de clientes para la autenticación en una aplicación Xamarin Forms para iOS, pero parece que nada funciona. Si comienzo la solicitud, la aplicación espera al tiempo de espera predeterminado de 100 segundos (intenté disminuirla con HttpWebRequest.Timeout, pero parece que se ignora su configuración), después de eso obtengo la siguiente excepción: Error al obtener la secuencia de respuesta (ReadDone1) : ReceiveFailure
El mismo código que una aplicación de consola de Windows funciona bien. Aquí algunos fragmentos (simplificados para la lectura) para reproducir:
Cliente:
var clientCertificate = new X509Certificate2(data, pwd);
var result = await ExecuteRequest("https://server/user.aspx", clientCertificate);
public static async Task<string> ExecuteRequest(Uri uri, X509Certificate2 clientCertificate)
{
var hwr = (HttpWebRequest)HttpWebRequest.Create(uri);
if (clientCertificate != null)
{
hwr.ClientCertificates.Add(clientCertificate);
}
hwr.Method = "GET";
try
{
var resWebResonse = await hwr.GetResponseAsync();
var stream = resWebResonse.GetResponseStream();
var sr = new StreamReader (stream);
return sr.ReadToEnd();
}
catch (Exception ex)
{
Debug.WriteLine($"Error executing Webrequest to {uri}: {ex}");
}
return null;
}
Servidor: usuario.aspx
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Security.Cryptography.X509Certificates" %>
<%@ Import Namespace="System.Security.Principal" %>
<script runat="server">
public void Page_Load(object sender, EventArgs e)
{
try
{
Regex userRegEx = new Regex("CN=(.*)@", RegexOptions.IgnoreCase | RegexOptions.Compiled);
if (Request.ClientCertificate.IsPresent)
{
var cert = new X509Certificate2(Request.ClientCertificate.Certificate);
var identity = new GenericIdentity(cert.Subject, "ClientCertificate");
var principal = new GenericPrincipal(identity, null);
var m = userRegEx.Match (principal.Identity.Name);
Response.Write (m.Groups[1].Value);
}
else
Response.Write("No Client-Certificate");
Response.End();
}
catch (Exception ex)
{
if (!(ex is System.Threading.ThreadAbortException))
Response.Write(ex.ToString());
}
}
</script>
Esta es la excepción que sigo recibiendo:
System.Net.WebException: Error getting response stream (ReadDone1): ReceiveFailure
---> System.IO.IOException: Unable to read data from the transport connection: Connection reset by peer.
---> System.Net.Sockets.SocketException: Connection reset by peer
at System.Net.Sockets.Socket.Receive (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socketFlags) [0x00017]
in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/referencesource/System/net/System/Net/Sockets/Socket.cs:1773
at System.Net.Sockets.NetworkStream.Read (System.Byte[] buffer, System.Int32 offset, System.Int32 size) [0x0009b]
in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/referencesource/System/net/System/Net/Sockets/NetworkStream.cs:513
--- End of inner exception stack trace
---
at Mono.Net.Security.MobileAuthenticatedStream.EndReadOrWrite (System.IAsyncResult asyncResult, Mono.Net.Security.AsyncProtocolRequest& nestedRequest) [0x00056]
in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/System/Mono.Net.Security/MobileAuthenticatedStream.cs:335
at Mono.Net.Security.MobileAuthenticatedStream.EndRead (System.IAsyncResult asyncResult) [0x00000]
in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/System/Mono.Net.Security/MobileAuthenticatedStream.cs:278
at System.Net.WebConnection.ReadDone (System.IAsyncResult result) [0x00027]
in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/System/System.Net/WebConnection.cs:475
--- End of inner exception stack trace
---
at System.Net.HttpWebRequest.EndGetResponse (System.IAsyncResult asyncResult) [0x00059]
in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/System/System.Net/HttpWebRequest.cs:1031
at System.Threading.Tasks.TaskFactory`1[TResult].FromAsyncCoreLogic (System.IAsyncResult iar, System.Func`2[T,TResult] endFunction, System.Action`1[T] endAction, System.Threading.Tasks.Task`1[TResult] promise, System.Boolean requiresSynchronization) [0x0000f]
in <6314851f133e4e74a2e96356deaa0c6c>:0
--- End of stack trace from previous location where exception was thrown
---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c]
in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:151
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00037] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.0.0.0/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128
at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000]
in <6314851f133e4e74a2e96356deaa0c6c>:0
at EWOIS.iOS.WebHelper+<ExecuteRequest>d__4.MoveNext () [0x0012e] in C:/xxxx/WebHelper.cs:70
- Visual Studio 2017 v15.3.5
- Xamarin 4.7.9.45
- Xamarin iOS y Xamarin Mac SDK 11.0.0.0
- Deployment Target iOS 9.3 (10.3 no funciona tan bien)
- Windows Server 2008 R2 Enterprise SP1
- IIS 7
Agregué un cheque para el certificado del servidor (que está firmado por nuestro dominio-CA) en AppDelegate.cs, informa SslPolicyErrors.None
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) =>
{
if (cert != null)
System.Diagnostics.Debug.WriteLine($"Servercertificate: {cert.Subject}, SSL-Policy-Errors: {sslPolicyErrors}");
return sslPolicyErrors == SslPolicyErrors.None; // return true does not work either (and is not recommended for security reasons)
}
La solicitud funciona si deshabilito el requisito de certificado en el servidor web, por lo que la conexión está funcionando.
Incluso probé System.Net.HttpClient , pero arroja una NotImplementedException al acceder a la propiedad ClientCertificate :(
Ahora no tengo ni idea de qué probar a continuación ... todas las demás preguntas que encontré tenían algunos años y no ofrecen ninguna solución funcional
Encontré varias preguntas que apuntan a un problema con la pila Mono HTTP. Puede ayudar a resolver su problema: Cómo validar certificados SSL al usar HttpWebRequest , se necesita ayuda urgente: "error al obtener la secuencia de respuesta (ReadDone1): ReceiveFailure" . Una de las formas posibles es usar ModernHttpClient que utiliza un cliente HTTP nativo de la plataforma.
También tiene un error en la devolución de llamada en la propiedad ServicePointManager.ServerCertificateValidationCallback . RemoteCertificateValidationCallback delegate devuelve un valor booleano que determina si el certificado especificado se acepta para la autenticación. Ver más detalles en ejemplos de MSDN. También intente leer la pregunta Cómo validar certificados SSL al usar HttpWebRequest .
¿Qué sucede si se conecta al servidor a través de HTTPS sin agregar específicamente el certificado?
¿La solicitud llega al servidor? Si es así, el problema probablemente esté en la decodificación de la respuesta cifrada. ¿Los certificados en el cliente y el servidor son iguales?