Android BouncyCastle (SpongyCastle) HTTPS POST 请求
Android BouncyCastle (SpongyCastle) HTTPS POST request
我正在尝试使用 BouncyCastle (SpongyCastle) 库在旧 Android 设备 运行 Jellybean 4.1.2 上登录我的 TLS1.2 服务器,但它不起作用。 Android 的那个版本默认没有启用 TLS,所以我需要第 3 方库才能使用它。
有两个问题。
1. 我收到 HTTP 302 而不是 JSON 响应。
2. 我不知道如何发送 JSON 有效载荷(对于其他端点,我将使用
对于 HTTP 302,我得到以下响应:
Result: HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Cache-Control: private
Expires: Thu, 01 Jan 1970 00:00:00 UTC
Set-Cookie: JSESSIONID=83C535625CDEF9DEC3D7890F1A9C86B0; Path=/; Secure; HttpOnly
Location: https://www.google.com/login/auth Content-Length: 0
Date: Wed, 14 Mar 2018 15:32:19 GMT
Via: 1.1 google
Set-Cookie: GCLB=CMfzgbfeh7bLpwE; path=/; HttpOnly
Alt-Svc: clear
Connection: close
所以它似乎试图重定向到某种 Google 登录,这很奇怪。
此外,对于上面的数字 2,我正在尝试发送有效载荷,我是只添加另一个 output.write(myJSONPayload);
还是必须做其他事情?
我的代码如下:
{
java.security.SecureRandom secureRandom = new java.security.SecureRandom();
Socket socket = new Socket("www.myserver.com", 443);
TlsClientProtocol protocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), secureRandom);
DefaultTlsClient client = new DefaultTlsClient() {
public TlsAuthentication getAuthentication() throws IOException {
TlsAuthentication auth = new TlsAuthentication() {
// Capture the server certificate information!
public void notifyServerCertificate(Certificate serverCertificate) throws IOException {
}
public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException {
return null;
}
};
return auth;
}
};
protocol.connect(client);
java.io.OutputStream output = protocol.getOutputStream();
output.write("GET / HTTP/1.1\r\n".getBytes("UTF-8"));
//Get auth with my own class to generate base 64 encoding
output.write(("Authorization: " + BasicAuthentication.getAuthenticationHeader("myuser", "mypass")).getBytes());
output.write("Host: www.myserver.com/logon\r\n".getBytes("UTF-8"));
output.write("Connection: close\r\n".getBytes("UTF-8")); // So the server will close socket immediately.
output.write("\r\n".getBytes("UTF-8")); // HTTP1.1 requirement: last line must be empty line.
output.flush();
java.io.InputStream input = protocol.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = reader.readLine()) != null) {
Log.d(TAG, "--> " + line);
sb.append(line).append("\n");
}
} catch (TlsNoCloseNotifyException e) {
Log.d(TAG, "End of stream");
}
String result = sb.toString();
Log.d(TAG, "Result: " + result);
}
另一个问题,我是否指定了正确的主机?我在 Socket
中使用基础 URL,在 OutputStream
中使用完整的 URL 是否正确?
这里的解决方案是将此方法添加到我的自定义 SSLSocketFactory 中:
private static void setupSecurityForTLS() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
Log.d(TAG, "Adding new security provider");
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
Security.insertProviderAt(new BouncyCastleProvider(), 2);
}
}
并在我初始化套接字之前调用它。
您还可以将这两行添加到 class 顶部的静态初始化程序,例如:
static {
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
Security.insertProviderAt(new BouncyCastleProvider(), 2);
}
我正在尝试使用 BouncyCastle (SpongyCastle) 库在旧 Android 设备 运行 Jellybean 4.1.2 上登录我的 TLS1.2 服务器,但它不起作用。 Android 的那个版本默认没有启用 TLS,所以我需要第 3 方库才能使用它。
有两个问题。 1. 我收到 HTTP 302 而不是 JSON 响应。 2. 我不知道如何发送 JSON 有效载荷(对于其他端点,我将使用
对于 HTTP 302,我得到以下响应:
Result: HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Cache-Control: private
Expires: Thu, 01 Jan 1970 00:00:00 UTC
Set-Cookie: JSESSIONID=83C535625CDEF9DEC3D7890F1A9C86B0; Path=/; Secure; HttpOnly
Location: https://www.google.com/login/auth Content-Length: 0
Date: Wed, 14 Mar 2018 15:32:19 GMT
Via: 1.1 google
Set-Cookie: GCLB=CMfzgbfeh7bLpwE; path=/; HttpOnly
Alt-Svc: clear
Connection: close
所以它似乎试图重定向到某种 Google 登录,这很奇怪。
此外,对于上面的数字 2,我正在尝试发送有效载荷,我是只添加另一个 output.write(myJSONPayload);
还是必须做其他事情?
我的代码如下:
{
java.security.SecureRandom secureRandom = new java.security.SecureRandom();
Socket socket = new Socket("www.myserver.com", 443);
TlsClientProtocol protocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), secureRandom);
DefaultTlsClient client = new DefaultTlsClient() {
public TlsAuthentication getAuthentication() throws IOException {
TlsAuthentication auth = new TlsAuthentication() {
// Capture the server certificate information!
public void notifyServerCertificate(Certificate serverCertificate) throws IOException {
}
public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException {
return null;
}
};
return auth;
}
};
protocol.connect(client);
java.io.OutputStream output = protocol.getOutputStream();
output.write("GET / HTTP/1.1\r\n".getBytes("UTF-8"));
//Get auth with my own class to generate base 64 encoding
output.write(("Authorization: " + BasicAuthentication.getAuthenticationHeader("myuser", "mypass")).getBytes());
output.write("Host: www.myserver.com/logon\r\n".getBytes("UTF-8"));
output.write("Connection: close\r\n".getBytes("UTF-8")); // So the server will close socket immediately.
output.write("\r\n".getBytes("UTF-8")); // HTTP1.1 requirement: last line must be empty line.
output.flush();
java.io.InputStream input = protocol.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
StringBuilder sb = new StringBuilder();
try {
while ((line = reader.readLine()) != null) {
Log.d(TAG, "--> " + line);
sb.append(line).append("\n");
}
} catch (TlsNoCloseNotifyException e) {
Log.d(TAG, "End of stream");
}
String result = sb.toString();
Log.d(TAG, "Result: " + result);
}
另一个问题,我是否指定了正确的主机?我在 Socket
中使用基础 URL,在 OutputStream
中使用完整的 URL 是否正确?
这里的解决方案是将此方法添加到我的自定义 SSLSocketFactory 中:
private static void setupSecurityForTLS() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
Log.d(TAG, "Adding new security provider");
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
Security.insertProviderAt(new BouncyCastleProvider(), 2);
}
}
并在我初始化套接字之前调用它。
您还可以将这两行添加到 class 顶部的静态初始化程序,例如:
static {
Security.insertProviderAt(new BouncyCastleJsseProvider(), 1);
Security.insertProviderAt(new BouncyCastleProvider(), 2);
}