I'm trying to connect to a web server for my application that requires an SSL client certificate for authentication. From the standard documentation, I can't tell how to reuse an SSL session for multiple requests (I don't want to have to a full SSL handshake for every single request as this causes major overhead). Can someone point me in the right direction?
EDITI've seen in other posts that HttpClient might be a solution but as of Android 6.0 this has been deprecated in favor of HttpsUrlConnection. Using the following code:
SSLContext sslContext;
HttpsUrlConnection connection = url.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
Does a new FULL SSL handshake occur (probably right?) everytime I create a new connection. How do I reuse the session?
I can't tell how to reuse an SSL session for multiple requests
It's automatic.
(I don't want to have to a full SSL handshake for every single request as this causes major overhead)
It would cause major overhead, if it ever happened, but it doesn't.
Does a new FULL SSL handshake occur (probably right?) everytime I create a new connection?
No.
How do I reuse the session?
It should happen by default, subject to session timeouts at the server.
Related
I'm using the TRESTClient, TRESTRequest, TRESTResponse component stack for communication with the https REST API service. The Server authenticates the client by sending the request using the client certificate.
In my Android application, after calling the RestRequest.Execute (rmPost) method, a form appears asking for the selection of the client certificate. I would like to automatically assign a client certificate and avoid this additional question, but the RESTClient.OnNeedClientCertificate event is not fired.
I checked RESTLibrary, and I separately checked TNetHttpClient (the event OnNeedClientCertificate is also not fired), after several hours of reading blogs and performing dozen of tests, I am so frustrated as I have no idea how to solve the problem.
How can I avoid this additional question about choosing a client certificate and set the client certificate automatically?
Why is the TRESTClient.OnNeedClientCertificate event is not fired?
Thank you for any suggestions and help.
We need to perform certificate based client authentication to a server accepting only TLS 1.3 connections.
The server is using Apache 2 and HTTP 1.1 and is configured to allow client cert auth but not to enforce it because some resources require client auth while others don't.
We're using OkHttp 4.9.1 on Android 11 to perform the call and we're following the standard docs on how to perform client auth: https://github.com/square/okhttp/tree/master/okhttp-tls
The server however replies with: 403 (auth renegotiation not allowed)
This is in line with TLS 1.3 specification which does not allow auth renegotation unless agreed upon during the initial handshake.
So far we've debugged the connection and inside OkHttp the class RealConnection and it actually performs the Handshake without negotiating a client cert.
Our research so far indicates that this might be due to the server using OPTIONAL ssl client auth but this is not somethign we can change so....
Is there any other option we can pass during OkHttp initialization to force it to perform the initial handshake using the client cert?
in case OkHttp is not a viable option is there any other HTTP client implementation which would allow us to force such authetnication during the initial handshake?
Create a HandshakeCertificates object using its builder. You'll need your private key, client cert and any intermediates on the client side.
The client will also need a root certificate for your server to trust it. The builder has a function to use the built in certificate authorities for that if you like.
private OkHttpClient buildClient(
HeldCertificate heldCertificate, X509Certificate... intermediates) {
HandshakeCertificates.Builder builder = new HandshakeCertificates.Builder()
.addTrustedCertificate(serverRootCa.certificate());
if (heldCertificate != null) {
builder.heldCertificate(heldCertificate, intermediates);
}
HandshakeCertificates handshakeCertificates = builder.build();
return clientTestRule.newClientBuilder()
.sslSocketFactory(
handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager())
.build();
}
https://github.com/square/okhttp/blob/1ce86f35a9d957bae711fb81cec60abe9f43dda0/okhttp/src/test/java/okhttp3/internal/tls/ClientAuthTest.java#L126
Optional client certificate authentication is no different from required client certificate authentication from the perspective of the client. All what the client sees is a CertificateRequest and as a response it will send some certificates (leaf and chain), which might also be an empty list of certificates. It is up to the server to decide if this is acceptable, i.e. optional simply means that the server accepts that the client sends an empty list of certificates.
The problem thus is not optional or required client certificates, but that the server has not requested a certificate at all in the initial TLS handshake and likely only requests a certificate when accessing a specific path (the requested path can only be seen after the initial handshake). With Apache this is typically the case if client certificate is not requested in the server global configuration but instead in a path specific .htaccess file. Fix would be to move the requirement at the level of the domain and not the path only.
I know that this question is answered several times but i couldn't figure out how should i do this.
How should i send critical information like passwords etc. My Host provider grants SSL certification.
Should i do it with HttpPost or it needs to be more secured.
Here is my POST snippet.
HttpPost post = new HttpPost("http://example.com/");
NameValuePair[] data = {
new NameValuePair("a", "b"),
new NameValuePair("c", "d")
};
post.setRequestBody(data);
InputStream in = post.getResponseBodyAsStream();
Any help would be appreciated.
You are confusing the request type (POST, GET, etc) with the transport method (HTTP, HTTPS).
If you have been provided with an SSL cert you should set your server up to listen on a secure connection (usually 443 for HTTPS, but not necessarily for a server).
Your calls should then be routed to https://[your_server]/. They will then be secure.
And really, you should look into using a library for making requests. You are probably going to hit the 'network traffic on the main thread' warning quite soon. Look into 'Fast Android Networking' or 'Volley'.
I am using android nv-websocket-client library (both 2.0 and 1.31 versions) and I am trying to open a wss: connection; however, the connection fails with 503 Service not available error message.
Upon investigating I found that HAProxy requires the clients to use the SNI extension, otherwise such error is returned regardless of the Host: header (I am using HAProxy as a loadbalancer).
Upon investigating further (with tcpdump/wireshark) I found that the client does not send SNI, a wrong certificate is returned (for a different domain), yet the client continues with the TLS connection and actually sends the HTTP request (as if no certificate checking was performed?).
My code is basically:
ws = new WebSocketFactory().createSocket(wsurl);
ws.addHeader("Authorization", "Bearer " + Config.getToken());
ws.addListener(this);
ws.connectAsynchronously();
I didn't find an easy way to set up the SSLSocketFactory, however it seems to me that the code in nv-websocket-client just uses the SSLSocketFactory.getDefault(), which should be correct? SSLCertificateSocketFactory seems to be deprecated in favour of this approach.
Am I missing some key piece about SSL setup, is this and Android bug or is this and Android 'feature'?
I'm trying to implement a RESTful web service using Spring. I've set up Spring Security to work on the links that apply to the REST service. I make calls to this web service from an Android application. What I've done now is connect to it using Basic Authentication. What I'm struggling with is finding decent information about how secure this really is. I figure I should at least be making these calls through SSL or something no?
My code on the Android client that calls the REST client
public MyClass callRest() {
final String url = "http://10.0.2.2:8080/myservice/rest/getSomething";
HttpAuthentication authHeader = new HttpBasicAuthentication(username,
password);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(authHeader);
requestHeaders.setAccept(Collections
.singletonList(MediaType.APPLICATION_JSON));
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(
new MappingJacksonHttpMessageConverter());
try {
ResponseEntity<MyClass> response = restTemplate.exchange(url,
HttpMethod.GET, new HttpEntity<Object>(requestHeaders),
MyClass.class);
return response.getBody();
} catch (HttpClientErrorException e) {
return new MyClass();
}
}
So what I've put in my Spring Security config right now:
<http auto-config='true'>
<intercept-url pattern="/rest/**" access="ROLE_USER"
requires-channel="https" />
</http>
I can't figure out where to go from there, because now the connection doesn't work anymore of course because of the https. I can't seem to find decent examples of how to figure this out using the Resttemplate.
Any help?
HTTP Basic Authentication is reasonably safe when used over HTTPS since the user and password fields are sent over an encrypted connection so they are much less vulnerable to man-in-the-middle attacks. There are some interesting points here: Securing an API: SSL & HTTP Basic Authentication vs Signature
In my opinion, if you are making a API with access to user's sensitive data (i.e. bank account details, credit card numbers, email addresses and passwords) then you may want a more secure approach because HTTP Basic Authentication is succeptible to brute force attacks as it is always available (unless you build in deterrents such as maximum retries etc.) If your API is for a game or basic business data then there should be less attraction for a hacker to spend the time on it.
Does your server support HTTPS - often you need to pay extra for a HTTPS certificate or you have to use a shared once which give you a subdomain on a shared HTTPS domain - i.e. https//your-site.your-hosting-provider.com/. You need to check this perhaps.
UPDATE 1: Your problem appears to be with your server and not with your program. Check out this blog post for information about how to set up HTTPS on your Tomcat Server. You need to do this before you can use HTTPS from your Spring application - looking at your code, there doesn't seem to be a problem other than your server.
Also try this.
UPDATE 2 Once you have access, you will then need to trust the certificate on the Android device (or your Java installation if you were making a desktop/web application). It needs to be trusted because you created it yourself rather than a CA authority. See this answer: Trusting all certificates using HttpClient over HTTPS (Not the part about trusting all certificates - this can be dangerous).