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

时间:2014-08-17 15:36:07

标签: java android ssl https ssl-certificate

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

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

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

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

我找不到服务器EventVwr中的错误。

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

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

请帮忙。

编辑1

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

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

编辑2

在你的评论中读到之后,现在我让Fiddler玩得很好(感谢this question)。 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不显示任何消息提示(可能在转换为消息之前丢弃),但跟踪显示: The WCF Trace as seen from the SvcTraceViewer

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

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

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)

2 个答案:

答案 0 :(得分:2)

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

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

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

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

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

HTH!

答案 1 :(得分:0)

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

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

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