使用客户端证书和Android的HttpsURLConnection通过SSL上传文件

我正在尝试将文件上传到受SSL保护的Web服务,并且需要客户端证书(由内部CA签名)。 与上传文件相比 ,与Web服务的通信运行良好(下载文件,查询,运行命令和执行各种POST工作正常)。

上传文件时,我得到一个SSLException(javax.net.ssl.SSLException),上面写着“写入错误:ssl = 0x5fe209c0:系统调用期间的I / O错误,同步连接重置”。

我创建了一个重复的服务器并删除了SSL和客户端证书要求,并尝试通过’vanilla’HTTP上传,并且它运行良好。

我尝试过使用setFixedLengthStreamingMode(int)和setChunkedStreamingMode(int)但没有成功。 使用它们时,会从write方法抛出exception,并且当不使用它们中的任何一个时,从getResponseCode()的调用中抛出相同的exception。

我在服务器的EventVwr找不到任何关于错误的EventVwr

我们的其他客户端(iOS客户端)能够在那里上传文件,所以它必须是我做的 – 但我无法弄清楚是什么。

我不确定如何进一步调试此问题。

请帮忙。

编辑1

我们做了很多调试工作,发现:

  • 小文件按预期上传(44kb是成功上传的最大文件的大小,并在~1200ms上传)。
  • 46kb文件无法上传。 失败大约需要2分钟(134120ms)。

编辑2

在你的评论中读到之后,现在我让Fiddler玩得很好(感谢这个问题 )。 Fiddler得到了这个文件,但没有成功发送它。 请求(原始)看起来像:

 POST https://192.168.2.2/rest/transfer/strong/Upload/Full?Path=%5C20140807_113255_20.jpg&Root=2 HTTP/1.1 SessionToken: 1234 // We use this for session management FileMetadata: {"FileSize":"1315496","FileName":"GrumpyCat.jpg"} Connection: Keep-Alive User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.1; GT-N7100 Build/JRO03C) Host: 192.168.2.2 Accept-Encoding: gzip Content-Type: application/x-www-form-urlencoded Content-Length: 1315496 ;odiao;awriorijgoeijoeirj;oedfrvgerg... // The image 

Fiddler的回应(也是RAW)是:

 HTTP/1.1 504 Fiddler - Send Failure Date: Wed, 20 Aug 2014 17:40:29 GMT Content-Type: text/html; charset=UTF-8 Connection: close Timestamp: 20:40:29.420 [Fiddler] ResendRequest() failed: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host. < An existing connection was forcibly closed by the remote host 

此外,我们添加了WCF的 ‘MessageLogging’和详细的’Tracing’。 MessageLogging不显示任何消息提示(可能在转换为消息之前丢弃),但跟踪显示: 从SvcTraceViewer看到的WCF跟踪

现在,在您说“啊,这是服务器问题”之前,请记住44kb文件成功上传,我们的iOS应用程序也能够成功上传文件。

这是来自客户端获取的exception的调用堆栈:

 E/RestClientUploader(3196): javax.net.ssl.SSLException: Write error: ssl=0x5d94b8b0: I/O error during system call, Connection reset by peer E/RestClientUploader(3196): at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native Method) E/RestClientUploader(3196): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:693) E/RestClientUploader(3196): at java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:231) E/RestClientUploader(3196): at libcore.net.http.ChunkedOutputStream.writeBufferedChunkToSocket(ChunkedOutputStream.java:129) E/RestClientUploader(3196): at libcore.net.http.ChunkedOutputStream.write(ChunkedOutputStream.java:77) E/RestClientUploader(3196): at java.io.DataOutputStream.write(DataOutputStream.java:98) E/RestClientUploader(3196): at com.varonis.datanywhere.communication.RestClientUploader.uploadFileToServer(RestClientUploader.java:151) E/RestClientUploader(3196): at com.varonis.datanywhere.communication.RestClientUploader.uploadFullFile(RestClientUploader.java:67) E/RestClientUploader(3196): at com.varonis.datanywhere.communication.services.FileUploadService.doUpload(FileUploadService.java:128) E/RestClientUploader(3196): at com.varonis.datanywhere.communication.services.FileUploadService.onHandleIntent(FileUploadService.java:98) E/RestClientUploader(3196): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65) E/RestClientUploader(3196): at android.os.Handler.dispatchMessage(Handler.java:99) E/RestClientUploader(3196): at android.os.Looper.loop(Looper.java:137) E/RestClientUploader(3196): at android.os.HandlerThread.run(HandlerThread.java:60) 

Related of "使用客户端证书和Android的HttpsURLConnection通过SSL上传文件"

不是答案,更多是解决方案 – 供您参考。

在围绕这个问题抨击并进行大量研究之后,我们放弃了。 我们已经向Google开放了此问题 ,并实施了以下工作:

为了上传文件,应用程序首先通过需要客户端证书的端点获取上传令牌 ,然后使用此令牌上传到不需要客户端证书的端点(但仍然通过SSL(Https) )。

是的,这是一个轻微的安全漏洞,但我们不得不这样做。 我们尽可能地保护它……

我保证会更新Google的故障单(并希望解决)。

HTH!

这有点晚了(因为你已经实现了一个解决方法),但这应该可以解决问题: https : //stackoverflow.com/a/9224892/1619545

我们遇到了同样的问题,将客户端证书协商标志设置为启用似乎是帽子帮助的唯一问题。 看看如何在cert绑定中更改标志的方法:

http://help.sap.com/saphelp_smp305svr/helpdata/en/6f/f0a9b6e1c743d48d1e57235d297c1c/content.htm