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

Fel*_*lix 25 java ssl https android 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玩得很好(感谢这个问题).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
Run Code Online (Sandbox Code Playgroud)

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                                                                                                                                                                                                                                                                                                              
Run Code Online (Sandbox Code Playgroud)

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

现在,在您说"啊,这是服务器问题"之前,请记住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)
Run Code Online (Sandbox Code Playgroud)

Fel*_*lix 2

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

在对这个问题进行了一番思考并进行了大量研究之后,我们放弃了。我们已向Google 提出此问题,并实施了以下解决方案:

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

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

我保证在谷歌的票证更新时更新(并希望得到解决)。