我正在尝试在适用于 iOS 的 Xamarin Forms 应用程序中使用客户端证书进行身份验证,但似乎没有任何效果。如果我启动请求,应用程序等待默认超时 100 秒(我尝试使用 HttpWebRequest.Timeout 降低它,但设置它似乎被忽略),之后,我收到以下异常:获取响应流时出错(ReadDone1):接收失败
与 Windows 控制台应用程序相同的代码工作正常。这里有一些(为便于阅读而简化的)片段要重现:
客户:
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;
}
服务器:user.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>
这是我不断遇到的异常:
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 和 Xamarin Mac SDK 11.0.0.0
- 部署目标 iOS 9.3(10.3 也不起作用)
- Windows Server 2008 R2 企业版 SP1
- IIS 7
我在 AppDelegate.cs 中添加了对服务器证书(由我们的域 CA 签名)的检查,它报告 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)
}
如果我在 Web 服务器上禁用证书要求,则请求有效,因此连接正常。
我什至尝试过 System.Net.HttpClient,但在访问 ClientCertificate 属性时抛出一个 NotImplementedException :(
现在我完全不知道接下来要尝试什么......我发现的所有其他问题都是几年前的,没有提供任何有效的解决方案
最佳答案
在您的异常处理程序中,您似乎没有调用 Response.End():
catch (Exception ex)
{
if (!(ex is System.Threading.ThreadAbortException))
Response.Write(ex.ToString());
}
因此,如果在服务器端抛出异常,则响应可能永远不会发送到客户端。我建议添加一些异常的服务器端日志记录,看看是否以这种方式提供了任何有用的东西。
此外,您似乎验证了客户端证书的某些字段,但据我所知,您并未验证客户端证书是否由受信任的根签名。您应该确保是这种情况,否则任何人都可以生成包含他们想要模拟的用户名的自签名证书并使用它来欺骗您的代码,这将是一个严重的安全漏洞。
关于c# - 带有客户端证书的 Xamarin Forms https 抛出 WebException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46561938/