通过 SSL 的 Web 服务请求在 Monotouch v4.0.4.1 上引发 WebException:
'Error getting response stream (Write: The authentication or decryption has failed)'
由于服务器的 SSL 证书是自签名的(顺便说一句,我认为它不是 X.509),因此我使用 ServicePointManager.ServerCertificateValidationCallback 绕过了证书验证。完全相同的代码在 Windows .NET 上运行良好,其中 Web 服务调用返回正确的结果。在 Monotouch 上添加 Writeline 显示永远不会到达 ServerCertificateValidationCallback 委托(delegate)代码。
注意:虽然可能不相关,但请求的内容是带有嵌入式 WS-Security UsernameToken 的 SOAP。
有人在 MonoTouch 上有类似的东西吗?见过类似症状的报告,但没有解决。代码和堆栈跟踪如下,欢迎任何评论。如果需要,可以通过电子邮件发送独立的测试用例。
我发现有一种替代方法,使用 certmgr.exe 将自签名服务器证书存储在本地信任存储中,但似乎无法在 MonoTouch 发行版中找到该应用程序。有人能指点我吗?
..
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args);
}
}
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// If you have defined a view, add it here:
// window.AddSubview (navigationController.View);
string soapResponse;
string soapRequest = @" SOAP envelope is here but omitted for brevity ";
soapResponse = WebService.Invoke("myOperation", soapRequest);
window.MakeKeyAndVisible ();
return true;
}
// This method is required in iPhoneOS 3.0
public override void OnActivated (UIApplication application)
{
}
}
public class WebService
{
public static string Invoke(string operation, string soapRequest)
// Input parameters:
// operation = WS operation name
// soapRequest = SOAP XML request
// Output parameter:
// SOAP XML response
{
HttpWebResponse response;
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, ssl) => true;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://myserver.com:7570/MyEndpoint");
request.Method = "POST";
request.Headers.Add("SOAPAction", "/MyEndpoint/" + operation);
request.ContentType = "text/xml;charset=UTF-8";
request.UserAgent = "Smartphone";
request.ContentLength = soapRequest.Length;
request.GetRequestStream().Write(System.Text.Encoding.UTF8.GetBytes(soapRequest), 0, soapRequest.Length);
request.GetRequestStream().Close();
response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
{
return reader.ReadToEnd();
}
}
catch (WebException e)
{
throw new WebException(e.Message);
}
}
}
堆栈跟踪(一些名称已更改,以保护无辜者,可根据要求提供原始版本):
WS.WebService.Invoke (operation="myOperation", soapRequest="<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" \n\txmlns:ns1=\"http://mycompany/Common/Primitives/v1\" \n\txmlns:ns2=\"http://mycompany/Common/actions/externals/Order/v1\" \n\txmlns:ns3=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">\n\t<SOAP-ENV:Header> <wsse:Security SOAP-ENV:mustUnderstand=\"1\" \n\txmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"> \n\t<wsse:UsernameToken wsu:Id=\"UsernameToken-1\" \n\txmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"> \n\t<wsse:Username>myusername</wsse:Username> <wsse:Password \n\tType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">mypw</wsse:Password> \n\t<wsse:Nonce>{0}</wsse:Nonce> \n\t<wsu:Created xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">{1}</wsu:Created> \n\t</wsse:UsernameToken> </wsse:Security> \n\t</SOAP-ENV:Header><SOAP-ENV:Body><ns2:tp_getOrderDetailRequest><ns2:header><ns1:source>TEAM</ns1:source>\n\t<ns1:userAccessKey>12345678901234567</ns1:userAccessKey></ns2:header>\n\t<ns2:OrderId>myid1</ns2:OrderId>\n\t<ns2:OrderId>myid2</ns2:OrderId>\n\t</ns2:tp_getOrderDetailRequest>\n\t</SOAP-ENV:Body>\n\t</SOAP-ENV:Envelope>") in /Users/billf/Projects/WS/WS/Main.cs:103
WS.AppDelegate.FinishedLaunching (app={MonoTouch.UIKit.UIApplication}, options=(null)) in /Users/billf/Projects/WS/WS/Main.cs:52
MonoTouch.UIKit.UIApplication.Main (args={string[0]}, principalClassName=(null), delegateClassName=(null)) in /Developer/MonoTouch/Source/monotouch/monotouch/UIKit/UIApplication.cs:26
MonoTouch.UIKit.UIApplication.Main (args={string[0]}) in /Developer/MonoTouch/Source/monotouch/monotouch/UIKit/UIApplication.cs:31
WS.Application.Main (args={string[0]}) in /Users/billf/Projects/WS/WS/Main.cs:18
最佳答案
MonoTouch(就像 Mono)不支持 TLS_DH* 密码套件(例如 TLS_DHE_DSS_WITH_AES_128_CBC_SHA)。
当服务器配置为仅接受它们时,协商阶段会很早就失败(发送客户端 Hello 消息后从服务器收到警报),这解释了为什么从未调用回调.
确保您的服务器允许更传统的密码套件,例如非常安全(但速度较慢)的 TLS_RSA_WITH_AES_256_CBC_SHA 或更快(且非常常见)的密码套件:TLS_RSA_WITH_RC4_128_[MD5|SHA] 和 Mono[Touch] 应该可以很好地使用它们。
请注意,这与 SOAP 或 Web 服务(甚至 X.509 证书)无关 - 它只是普通的 SSL。
关于web-services - 通过 SSL 的 MonoTouch Web 服务请求获取 'authentication or decryption has failed',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6927140/