gpt4 book ai didi

java - 搜索 HTTPS Session 中的 SessionID、SessionKey

转载 作者:行者123 更新时间:2023-11-29 03:09:00 24 4
gpt4 key购买 nike

我正在尝试找到一种解决方案来获取 SessionID 和更重要的 SessionKey。我已经找到了一个基于 Java 的解决方案:

http://jsslkeylog.sourceforge.net

它使用以下类来记录 RSA-SessionKey:

/**
* Transformer to transform <tt>RSAClientKeyExchange</tt> and
* <tt>PreMasterSecret</tt> classes to log <tt>RSA</tt> values.
*/
public class RSAClientKeyExchangeTransformer extends AbstractTransformer {

public RSAClientKeyExchangeTransformer(String className) {
super(className, "<init>");
}

@Override
protected void visitEndOfMethod(MethodVisitor mv, String desc) {
String preMasterType = "Ljavax/crypto/SecretKey;";
if (className.endsWith("/PreMasterSecret")) {
preMasterType = "[B";
}
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, "encrypted", "[B");
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, "preMaster", preMasterType);
mv.visitMethodInsn(INVOKESTATIC, className, "$LogWriter$logRSA", "([B" + preMasterType + ")V");
}
}

在我的 android 应用程序中,我使用 DefaultHttpClient (org.apache.http.impl.client) 建立 HTTPS 连接。对于此连接,我试图找到 SessionKey。有人知道是否可以使用 android/java 方法读出 key 吗?如果没有,有人知道 key 生成是在哪里实现的吗?

最佳答案

我不认为这可以通过公共(public) API 完成。您可以获取 session ID,但没有公共(public)接口(interface)来获取 key 。

但是,我能够结合使用反射和 native 代码来访问底层 OpenSSL struct ,其中包含 session ID 和主 key 。所以这是可能的,但它一点也不安全,因为隐藏的成员和库不能保证保持不变。事实上,看起来 OpenSSL master 分支上的结构布局已经改变,因此如果/当它被拉入 Android 时,下面的解析代码将需要更新。

我使用 URL.openConnection() 而不是 DefaultHttpClient 来建立 HTTPS 连接,因为后者现在已被弃用。这是调用 URL.openConnection() 并替换默认的 SSLSocketFactory 的类(这里没什么有趣的):

public class MyConnection implements Runnable {
@Override
public void run() {
try {
// Create the connection.
URL url = new URL("https://www.google.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();

// Replace the default SSLSocketFactory with our own.
MySSLSocketFactory sslSocketFactory = new MySSLSocketFactory();
urlConnection.setSSLSocketFactory(sslSocketFactory);

// Establish the TLS connection.
int statusCode = urlConnection.getResponseCode();
Log.i("MyConnection", String.format("status %d", statusCode));

// Get SSL details from the captured socket.
sslSocketFactory.getSessionInfo();

} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();

}
}
}

这里是自定义 SSLSocketFactory,大部分的魔法都在这里。它所做的只是将覆盖的方法转发给真正的 SSLSocketFactory,缓存创建的 SSLSocket 实例。还有两个新的(未覆盖的)方法 - 下面进一步显示的 native 方法和 getSessionInfo() 使用 SSLSocket 上的反射来获取 native OpenSSL ssl_session_st 指针并解析(和记录)感兴趣的字段。请注意,您可以使用支持的 SSLSession.getId() 获取 session ID ;它正在获取需要偷偷摸摸的 key 。

// Use Decorator pattern to capture the SSL socket from the default SSLSocketFactory.
class MySSLSocketFactory extends SSLSocketFactory {
// Load NDK shared library.
static {
System.loadLibrary("my_native_helper");
}

// All overridden methods will be forwarded to the real SSLSocketFactory.
// The only addition is that the SSLSocket returned by createSocket() is
// cached.
SSLSocketFactory realFactory_ = HttpsURLConnection.getDefaultSSLSocketFactory();
SSLSocket s_;

// This native method copies data from a native pointer into a ByteBuffer.
native void readNative(long pointer, ByteBuffer dst);

// Use the cached SSLSocket to access native OpenSSL session data.
void getSessionInfo() throws NoSuchFieldException, IllegalAccessException {
// Get the protected OpenSSL ssl_session_st pointer. Note that this
// is not part of the API and could change across Android versions.
// See https://android.googlesource.com/platform/external/conscrypt/+/lollipop-mr1-dev/src/main/java/org/conscrypt/OpenSSLSessionImpl.java
SSLSession session = s_.getSession();
Field field = session.getClass().getDeclaredField("sslSessionNativePointer");
field.setAccessible(true);
long sessionPointer = field.getLong(session);

// Read as many bytes as we need from the native pointer.
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(104);
byteBuffer.order(ByteOrder.nativeOrder());
readNative(sessionPointer, byteBuffer);

// Parse the OpenSSL ssl_session_st. Note that the layout of this structure
// may change with OpenSSL versions and different compilers/platforms (e.g.
// 32-bit vs. 64-bit).
// See https://github.com/openssl/openssl/blob/OpenSSL_1_0_0-stable/ssl/ssl.h#L451
IntBuffer intBuffer = byteBuffer.asIntBuffer();
Log.i("MyConnection", String.format("SSL version %04x", intBuffer.get(0)));

int master_key_length = intBuffer.get(4);
String master_key = "";
for (int i = 0; i < master_key_length; ++i)
master_key += String.format("%02x", byteBuffer.get(20 + i));
Log.i("MyConnection", String.format("Master key %s", master_key));

int session_id_length = intBuffer.get(17);
String session_id = "";
for (int i = 0; i < session_id_length; ++i)
session_id += String.format("%02x", byteBuffer.get(72 + i));
Log.i("MyConnection", String.format("Session ID %s", session_id));
}

@Override
public String[] getDefaultCipherSuites() {
return realFactory_.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
return realFactory_.getSupportedCipherSuites();
}

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
s_ = (SSLSocket)realFactory_.createSocket(s, host, port, autoClose);
return s_;
}

@Override
public Socket createSocket(String host, int port) throws IOException {
s_ = (SSLSocket)realFactory_.createSocket(host, port);
return s_;
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
s_ = (SSLSocket)realFactory_.createSocket(host, port, localHost, localPort);
return s_;
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
s_ = (SSLSocket)realFactory_.createSocket(host, port);
return s_;
}

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
s_ = (SSLSocket)realFactory_.createSocket(address, port, localAddress, localPort);
return s_;
}
}

最后,这里是 native C 代码,可以从 native 指针将内存读入 ByteBuffer。这需要使用 Android NDK 构建并加载,如 MySSLSocketFactory 顶部所示。

#include <jni.h>
#include <string.h>

JNIEXPORT
void JNICALL Java_com_example_mysocketfactory_MySSLSocketFactory_readNative(
JNIEnv *env, jobject o,
jlong pointer, jobject buffer) {
const char *p = (const char *)pointer;
memcpy(
(*env)->GetDirectBufferAddress(env, buffer),
p,
(*env)->GetDirectBufferCapacity(env, buffer));
}

就是这样。在我的 KitKat 设备上调用 MyConnection.run() 时,日志显示:

I/MyConnection﹕ status 200
I/MyConnection﹕ SSL version 0301
I/MyConnection﹕ Master key 81ef39c5f8f7f796a34b307ff453511378fd081d14c37eb2e912fa829edf280e0fa7a499c370fdc156b8499758373d67
I/MyConnection﹕ Session ID b9ee4ae0c7738909430d47e9b0d6d60420d34a17d08181f21996e55a463aa5cf

我确实对 DefaultHttpClient 做了一个简短的尝试,但是当我不知道如何访问默认的 SchemeRegistry 时放弃了它。 .我认为这可以通过在构造 DefaultHttpClient 时指定 ClientConnectionManager 来完成,但我不想再继续使用已弃用的路径。如果您想尝试,那么您可能会使用类似的方法来拦截 SSLSessionImpl处理连接的实例。此类有一个 master_secret 成员,因此不需要本地代码,只需要反射(此代码路径不使用 OpenSSL)。

关于java - 搜索 HTTPS Session 中的 SessionID、SessionKey,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30530077/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com