尽管 servicePointManager hack,WebRequest 无法在 Xamarin.Forms 上使用 ssl

Nat*_*tle 3 mono xamarin.ios xamarin.android xamarin xamarin.forms

我正在编写一个需要从 REST api 读取的应用程序,该 api 只能通过 https 使用。我遇到了 Mono.Security 中请求失败的问题,并显示消息:“身份验证或解密失败。”

我做了我的研究,发现 Mono 默认情况下没有任何受信任的证书。我找到的所有来源都说我可以使用

ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });

在 iOS 和 Droid 项目中的 Main() 和 OnCreate() 方法中分别覆盖该检查并允许任何 ssl 证书。即使采用这种解决方法,我仍然遇到相同的错误。我已经单步执行了代码,并确认在 iOS 和 Android 上运行时会执行上述行。

我的代码在访问非 https API 时完美运行。这是一个 PCL 项目,而非共享项目。

我在问之前提到了这些问题/资源:

  • 忽略 Xamarin.Forms (PCL) 中的 SSL 证书错误
  • stackoverflow.com/questions/2675133/c-sharp-ignore-certificate-errors/2675183#2675183
  • bugzilla.xamarin.com/show_bug.cgi?id=6501
  • stackoverflow.com/questions/12287528/webclient-ssl-exception-with-android-4-and-mono-for-android
  • www.mono-project.com/docs/faq/security/

这是到目前为止的代码:

public class PawPrintsDataConnection
{
    private string response = "";
    private Task<string> StartWebRequest(string url)
    {

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.ContentType = "application/json";
        request.Method = "GET";

        Task<WebResponse> task = Task.Factory.FromAsync (request.BeginGetResponse, asyncResult => request.EndGetResponse (asyncResult), (object)null);
        return task.ContinueWith (t => ReadStreamFromResponse (t.Result));

    }
    private string ReadStreamFromResponse(WebResponse response)
    {
        using (Stream responseStream = response.GetResponseStream ())
        using (StreamReader sr = new StreamReader (responseStream)) {
            string strContent = sr.ReadToEnd ();
            return strContent;
        }
    }

    public string getRawResponse(){
        var task = StartWebRequest(string.Format (@"https://pawprints.rit.edu/v1/petitions?key={0}&limit={1}", "apikey", 50));

        this.response = task.Result;
        return response;
    }
}


public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
    protected override void OnCreate (Bundle bundle)
    {
        ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });

        base.OnCreate (bundle);

        global::Xamarin.Forms.Forms.Init (this, bundle);

        LoadApplication (new App ());
    }
}
static void Main (string[] args)
    {
        ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });
        // if you want to use a different Application Delegate class from "AppDelegate"
        // you can specify it here.
        UIApplication.Main (args, null, "AppDelegate");
        //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

    }
Run Code Online (Sandbox Code Playgroud)

在我的研究中,我在 Xamarin bugzilla 上发现了一个可能相关的错误,但我不确定它是否适用于我正在使用的版本。我对 Xamarin 开发人员很陌生,所以我不熟悉包含哪个版本的 Mono.security 之类的东西。https://bugzilla.xamarin.com/show_bug.cgi?id=26658

如果有帮助,这里是异常的相关部分:

System.AggregateException: One or more errors occurred ---> System.Exception: One or more errors occurred ---> System.Exception: Error: SendFailure (Error writing headers) ---> System.Exception: Error writing headers ---> System.Exception: The authentication or decryption has failed. ---> System.Exception: The authentication or decryption has failed.


at Mono.Security.Protocol.Tls.RecordProtocol.ProcessAlert (AlertLevel alertLevel, AlertDescription alertDesc) [0x00013] in ///Library/Frameworks/Xamarin.iOS.framework/Versions/8.6.1.26/src/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:654
at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x000dc] in ///Library/Frameworks/Xamarin.iOS.framework/Versions/8.6.1.26/src/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:377
Run Code Online (Sandbox Code Playgroud)

pou*_*pou 5

你访问pawprints.rit.edu对吗?

然后站点的证书(及其根 CA)就可以了,即 iOS 会接受它(并且 Xamarin.iOS 将信任决定委托给 iOS)。IOW 设置委托对您没有帮助(仅用于证书,这很好)。

这里的问题是服务器配置为仅允许一小部分 TLS 1.0 密码套件。它们都与HttpWebRequest.

您最好的选择是使用HttpClientCFNetworkHandler(对于iOS)或第三方句柄(例如ModernHttpClient 适用于iOS 和Android)。这将使用本机(来自操作系统)SSL/TLS 实现,它支持这些密码套件(以及更好的性能)。

  • 我使用了 ModernHttpClient 并摆脱了 ServicePointManager hack,它工作得很好。 (3认同)