使服务器仅接受来自 Android 应用程序的连接
Make server accept connections only from Android app
我想知道有没有办法让我的主机只接受来自我的应用程序的连接,并拒绝来自任何网络浏览器的连接。
最好的方法可能是将 SSL 与客户端证书一起使用。这将为您提供身份验证和加密。
在线支付时,您可能熟悉通过 HTTPS 使用 SSL 来保护您的 Web 浏览器。除了服务器还必须配置为需要客户端证书外,该过程类似。在 Apache 中,这是一个名为 SSLVerifyClient 的设置。这将强制 Web 服务器要求客户端提供证书,然后验证它是否有效。
从像威瑞信这样的根授权机构分配客户端证书可能很昂贵,因此您可能想要生成自己的证书。您可以使用 OpenSSL 执行此操作。
获得客户端证书后,您必须将证书复制到设备上的应用程序存储中。然后你可以使用 Keystore 对象打开它。打开后,您可以在使用 HttpUrlConnection 对象时将其与您的 HTTP 请求相关联。
由于您可能会生成自己的证书而不是使用来自根授权机构的证书,因此您需要在 Android 应用程序中设置一个 TrustManager 以接受您的自签名证书并将其与发出请求时的 HttpUrlConnection。
这是一般策略,应该足以让您入门。如果您卡在某个特定的问题上,请尝试针对不同的部分提出个别问题。 Apache 和 OpenSSL 部分最好发布在 Server Fault.
上
这里有一些服务器端的链接:
Client certificates with apache
Client-authenticated_TLS_handshake
以下是 Android 开发的链接:
HTTPS with Client Certificates on Android
android-ssl
FakeX509TrustManager(开发时有用)
看起来您所需的一切都在这些链接中,但我将在此处总结 Android 代码。请注意,我没有这方面的测试环境,因此代码不完整且未经测试。同样,这只是为了帮助您入门。
// open the certificate
keyStore = KeyStore.getInstance("PKCS12");
fis = new FileInputStream(certificateFile);
keyStore.load(fis, clientCertPassword.toCharArray());
// create the SSL context
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, clientCertPassword.toCharArray());
KeyManager[] keyManagers = kmf.getKeyManagers();
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
// perform the HTTP request
String result = null;
HttpURLConnection urlConnection = null;
try {
URL requestedUrl = new URL(url);
urlConnection = (HttpURLConnection) requestedUrl.openConnection();
if(urlConnection instanceof HttpsURLConnection) {
((HttpsURLConnection)urlConnection)
.setSSLSocketFactory(sslContext.getSocketFactory());
}
urlConnection.setRequestMethod("GET");
urlConnection.setConnectTimeout(1500);
urlConnection.setReadTimeout(1500);
lastResponseCode = urlConnection.getResponseCode();
result = IOUtil.readFully(urlConnection.getInputStream());
lastContentType = urlConnection.getContentType();
} catch(Exception ex) {
result = ex.toString();
} finally {
if(urlConnection != null) {
urlConnection.disconnect();
}
}
我想知道有没有办法让我的主机只接受来自我的应用程序的连接,并拒绝来自任何网络浏览器的连接。
最好的方法可能是将 SSL 与客户端证书一起使用。这将为您提供身份验证和加密。
在线支付时,您可能熟悉通过 HTTPS 使用 SSL 来保护您的 Web 浏览器。除了服务器还必须配置为需要客户端证书外,该过程类似。在 Apache 中,这是一个名为 SSLVerifyClient 的设置。这将强制 Web 服务器要求客户端提供证书,然后验证它是否有效。
从像威瑞信这样的根授权机构分配客户端证书可能很昂贵,因此您可能想要生成自己的证书。您可以使用 OpenSSL 执行此操作。
获得客户端证书后,您必须将证书复制到设备上的应用程序存储中。然后你可以使用 Keystore 对象打开它。打开后,您可以在使用 HttpUrlConnection 对象时将其与您的 HTTP 请求相关联。
由于您可能会生成自己的证书而不是使用来自根授权机构的证书,因此您需要在 Android 应用程序中设置一个 TrustManager 以接受您的自签名证书并将其与发出请求时的 HttpUrlConnection。
这是一般策略,应该足以让您入门。如果您卡在某个特定的问题上,请尝试针对不同的部分提出个别问题。 Apache 和 OpenSSL 部分最好发布在 Server Fault.
上这里有一些服务器端的链接:
Client certificates with apache
Client-authenticated_TLS_handshake
以下是 Android 开发的链接:
HTTPS with Client Certificates on Android
android-ssl
FakeX509TrustManager(开发时有用)
看起来您所需的一切都在这些链接中,但我将在此处总结 Android 代码。请注意,我没有这方面的测试环境,因此代码不完整且未经测试。同样,这只是为了帮助您入门。
// open the certificate
keyStore = KeyStore.getInstance("PKCS12");
fis = new FileInputStream(certificateFile);
keyStore.load(fis, clientCertPassword.toCharArray());
// create the SSL context
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, clientCertPassword.toCharArray());
KeyManager[] keyManagers = kmf.getKeyManagers();
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
// perform the HTTP request
String result = null;
HttpURLConnection urlConnection = null;
try {
URL requestedUrl = new URL(url);
urlConnection = (HttpURLConnection) requestedUrl.openConnection();
if(urlConnection instanceof HttpsURLConnection) {
((HttpsURLConnection)urlConnection)
.setSSLSocketFactory(sslContext.getSocketFactory());
}
urlConnection.setRequestMethod("GET");
urlConnection.setConnectTimeout(1500);
urlConnection.setReadTimeout(1500);
lastResponseCode = urlConnection.getResponseCode();
result = IOUtil.readFully(urlConnection.getInputStream());
lastContentType = urlConnection.getContentType();
} catch(Exception ex) {
result = ex.toString();
} finally {
if(urlConnection != null) {
urlConnection.disconnect();
}
}