上传文件通过SSL客户端证书和Android的HttpsURLConnection [英] Uploading a file over SSL with Client Side Certificate and Android's HttpsURLConnection

查看:285
本文介绍了上传文件通过SSL客户端证书和Android的HttpsURLConnection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将文件上载到被保护的SSL,需要一个客户端证书(通过一个内部CA签名)的Web服务。 到Web服务的通信效果很好(下载文件,查询,运行命令和执行各种职位的工作以及预期),除了上传文件

在上传文件,我得到一个异常SSLException(javax.net.ssl​​.SSLException),说:写错误:系统调用,将连接复位期间,I / O错误:SSL = 0x5fe209c0。

我创建了一个重复的服务器,并删除了SSL和客户端证书的要求,并试图上传过香草HTTP,和它完美的作品。

我已经试过用<一个href="http://developer.android.com/reference/java/net/HttpURLConnection.html#setFixedLengthStreamingMode(int)">setFixedLengthStreamingMode(int)和<一href="http://developer.android.com/reference/java/net/HttpURLConnection.html#setChunkedStreamingMode(int)">setChunkedStreamingMode(int)没有成功。当使用它们,除了从写抛出方法,当不使用其中任何一个,同样的异常从呼叫抛给 GETRESPONSE code()

我找不到有关该错误在服务器的 EVENTVWR 东西。

我们的其他客户端(IOS客户端)都可以上传文件存在,那么它必须是东西,我做的 - 但我想不出什么。

我不知道如何进一步调试这个问题。

请帮忙。

编辑1

我们已经做了很多的调试工作,并发现:

  • 小的文件被上传的预期效果(44KB是已成功上载的最大文件的大小,并将其在〜1200ms上载)。
  • 在一个46KB文件上传失败。失败了〜2分钟(134120ms)。

编辑2

在你阅读的话是什么,现在我得到了小提琴手发挥好(感谢<一href="http://stackoverflow.com/questions/16862916/fiddler-decrypt-android-httpsurlconnection-ssl-traffic">this问题)。提琴手拿到了文件,但在将其发送没有成功。 该请求(原始)是这样的:

  POST https://192.168.2.2/rest/transfer/strong/Uplo​​ad/Full?Path=%5C20140807_113255_20.jpg&Root=2 HTTP / 1.1
SessionToken:1234 //我们使用这个会话管理
FileMetadata:{文件大小:1315496,文件名:GrumpyCat.jpg}
连接:保持活动
用户代理:的Dalvik / 1.6.0(Linux的; U;安卓4.1.1; GT-N7100构建/ JRO03C)
主持人:192.168.2.2
接受编码:gzip
内容类型:应用程序/ x-WWW的形式urlen codeD
内容长度:1315496

; odiao; awriorijgoeijoeirj; oedfrvgerg ... //图像
 

提琴手的响应(也RAW)是:

  HTTP / 1.1 504提琴手 - 发送失败
日期:星期三,2014年8月20日17时40分29秒格林尼治标准​​时间
内容类型:text / html的;字符集= UTF-8
连接:关闭
时间戳:20:40:29.420

[提琴手] ResendRequest()失败:无法将数据写入传输连接:一个现有的连接被强行关闭远程主机。 &LT;一个现有的连接被强行关闭远程主机
 

此外,我们添加的 WCF的的'MessageLogging和冗长的跟踪。 MessageLogging不显示该消息的任何暗示(可能下降变成一个消息之前),但跟踪表明这样的:

现在,你之前说啊,这是一个服务器问题,请记住,44KB文件成功上传,和我们的iOS应用程序也能够成功地上传文件。

这是从所不同的是客户端获取调用堆栈:

  E / RestClientUploader(3196):javax.net.ssl​​.SSLException:写入错误:SSL = 0x5d94b8b0:系统调用过程中的I / O错误,将连接复位
E / RestClientUploader(3196):在org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(本机方法)
E / RestClientUploader(3196):在org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:693)
E / RestClientUploader(3196):在java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:231)
E / RestClientUploader(3196):在libcore.net.http.ChunkedOutputStream.writeBufferedChunkToSocket(ChunkedOutputStream.java:129)
E / RestClientUploader(3196):在libcore.net.http.ChunkedOutputStream.write(ChunkedOutputStream.java:77)
E / RestClientUploader(3196):在java.io.DataOutputStream.write(DataOutputStream.java:98)
E / RestClientUploader(3196):在com.varonis.datanywhere.communication.RestClientUploader.uploadFileToServer(RestClientUploader.java:151)
E / RestClientUploader(3196):在com.varonis.datanywhere.communication.RestClientUploader.uploadFullFile(RestClientUploader.java:67)
E / RestClientUploader(3196):在com.varonis.datanywhere.communication.services.FileUploadService.doUpload(FileUploadService.java:128)
E / RestClientUploader(3196):在com.varonis.datanywhere.communication.services.FileUploadService.onHandleIntent(FileUploadService.java:98)
E / RestClientUploader(3196):在android.app.IntentService $ ServiceHandler.handleMessage(IntentService.java:65)
E / RestClientUploader(3196):在android.os.Handler.dispatchMessage(Handler.java:99)
E / RestClientUploader(3196):在android.os.Looper.loop(Looper.java:137)
E / RestClientUploader(3196):在android.os.HandlerThread.run(HandlerThread.java:60)
 

解决方案

不是一个答案,更多的是变通 - 供大家参考

抨击我们的头脑解决此问题,并做了很多的研究后,我们放弃了。 我们已经打开这一问题与谷歌和各地采取了以下工作:

为了要上传的文件,应用程序首先获取一个的上传令牌的通过,需要客户端证书,之后使用该令牌上传来,不需要的端点的端点客户端证书(但仍通过SSL(HTTPS))。

是的,这是一个小的安全漏洞,但我们不得不这样做。我们保护它,就像我们可以...

我承诺更新时,谷歌的门票将被更新(希望解决)。

心连心!

I'm trying to upload a file to a web-service that is protected with SSL and requires a client-side certificate (signed by an in-house CA). The communication to the web-service works well (Downloading files, Querying, running commands and performing all sorts of POSTs works well as expected), except for uploading files.

When uploading files I get an SSLException (javax.net.ssl.SSLException) that says "Write error: ssl=0x5fe209c0: I/O error during system call, Connection reset by peer".

I have created a duplicate server and removed the SSL and Client-Certificate requirements, and tried to upload over 'vanilla' HTTP, and it works perfectly.

I've tried using setFixedLengthStreamingMode(int) and setChunkedStreamingMode(int) without success. When using them, the exception is thrown from the write method, and when not using any of them, the same exception is thrown from the call to getResponseCode().

I couldn't find anything about the error in the server's EventVwr.

Our other client (iOS client) is able to upload files there, so it must be something that I do - but I can't figure out what.

I'm not sure how to debug this issue further.

Please help.

Edit 1

We've done a lot of debugging efforts, and found that:

  • Small files are uploaded as expected (44kb is the size of the largest file that was uploaded successfully, and it uploaded in ~1200ms).
  • An 46kb file failed to upload. The failure took ~2 minutes (134120ms).

Edit 2

After what you'll read in the remarks, now I got Fiddler to play nice (Thanks to this question). Fiddler got the file, but did not succeed in sending it. The requests (raw) looks like:

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's response (also RAW) was:

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                                                                                                                                                                                                                                                                                                              

Also, We've added WCF's 'MessageLogging' and verbose 'Tracing'. MessageLogging don't show any hint of the message (probably dropped before turning into a message), but the trace showed this:

Now, before you say "ahhh, this is a server problem", keep in mind that 44kb files succeed in uploading, and our iOS app also is able to upload files successfully.

This is the call stack from the exception that the client gets:

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)

解决方案

Not an answer, more a work around - for your reference.

After bashing our heads around this issue, and doing a lot of research, we gave up. We've opened this issue with Google, and implemented the following work around:

In order to upload a file, the app first gets an Upload Token via an endpoint that requires the client-certificate, and afterwards uses this token to upload to an endpoint that doesn't require the client certificate (but still over SSL (Https)).

Yes, it's a minor breach of security, but we had to do it. We've protected it as much as we could...

I promise to update when the Google's ticket will be updated (and hopefully resolved).

HTH!

这篇关于上传文件通过SSL客户端证书和Android的HttpsURLConnection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆