2014-12-03 3 views
2

Если приложение Java создает ServerSocket, который принимает TCP-соединения, существует ли способ ограничить, какие процессы разрешены для подключения к нему?Как защитить ServerSocket, чтобы другие процессы не могли его использовать?

Например, это мой текущий код:

ServerSocket serverSocket = new ServerSocket(1234); 
Socket socket = serverSocket.accept(); 

, и я хочу, чтобы убедиться, что другие устройства в моей сети и даже другие процессы, работающие на той же машине, не в состоянии подключиться к нему (это если бы они это сделали). Я смог решить первое, связав serverSocket только с адресом loopback (проверка того, будет ли socket.getRemoteAddress() указывает на локальный хост), но я не смог найти способ ограничить его текущим процессом.

Это еще одна проблема при работе на Android. В моем приложении я хочу создать WebView (принадлежащий моему процессу) и указать его на serverSocket, но я не хочу, чтобы другие приложения могли подключаться к нему.

Есть ли способ решить эту проблему?

ответ

0

Я не думаю, что вы можете предотвратить подключение других процессов к серверу ServerSocket, но вы принимаете соединение, которое вы можете определить, принадлежит ли оно вам или другому процессу. Первый шаг, это выяснить, если соединение происходит от локального хоста:

InetSocketAddress remoteAddress = (InetSocketAddress) socket.getRemoteSocketAddress(); 
String hostname = remoteAddress.getHostName(); 
if (!hostname.equals("localhost")) { socket.close(); } 

В качестве альтернативы вы можете привязать сокет к кольцевому адресу, как 127.0.0.1 или 0.0.0.0 (как упоминалось EJP) и пропустить этот шаг. Как только вы узнаете, что соединение связано с localhost, все, что вам нужно сделать, это найти удаленный порт и выяснить, принадлежит ли его процессу.

int remotePort = remoteAddress.getPort(); 
if (ownPort(remotePort) == 1) { socket.close(); } 

Насколько я знаю, Java не имеет API, который можно использовать, чтобы вывести свои порты процесса, но вы определенно можете сделать это с помощью JNI.На стороне Java вы должны что-то вроде:

private native int doOwnPort(int port); 

И на родной стороне:

JNIEXPORT jint JNICALL Java_something_doOwnPort(JNIEnv *env, jobject object, jint port) { 
    long totalFDs = getdtablesize(); 
    struct sockaddr_in sa; 
    struct stat sb; 
    // Iterate through all file descriptors 
    for (int i = 0; i < totalFDs; ++i) { 
     // Check if "i" is a valid FD 
     memset(&sb, 0, sizeof(sb)); 
     if (fstat(i, &sb) < 0) 
      continue; 
     // Check if "i" is a socket 
     if (!S_ISSOCK(sb.st_mode)) 
      continue; 
     // Get local address of socket with FD "i" 
     memset(&sa, 0, sizeof(sa)); 
     socklen_t sa_len = sizeof(sa); 
     getsockname(i, (struct sockaddr*) &sa, &sa_len); 
     // Check if the port matches 
     if (sa.sin_port == port) 
      return 1; // We own the port 
    } 
    return -1; // We don't own the port 
} 

PS: Этот код предназначен для Linux, но должен работать на Android/Windows/OSX тоже.

Возможно, существует более прямой/эффективный способ проверить, принадлежит ли порт текущему процессу, не выполняя итерацию по таблице FD, но это отдельная проблема. НТН!

+0

Спасибо за это, но я не могу найти 'getdtablesize()' на Android. Можете ли вы показать мне, где это определено? –

+1

Используйте '#include ' или определите его сами как здесь: https://github.com/OpenWireSec/metasploit/blob/master/external/source/meterpreter/source/bionic/libc/unistd/getdtablesize.c –

+0

Yey! Это работает! Видимо, у Android NDK нет 'GE tdtablesize() 'в' unistd.h', но я использовал другую реализацию, и она работает. –

0

Вы можете получить этот тип безопасности

  • с помощью брандмауэров
  • реализации какой-то аутентификации самостоятельно на вашем ServerSocket. Запросить имя пользователя и пароль?

Розетки не предназначены для ограничения отдельных процессов.

+0

Спасибо, но пока брандмауэр был бы полезен для ограничения доступа с других устройств в сети, я не вижу как он может защитить от приложений, работающих на одном хосте. Пользовательская проверка подлинности является хорошей идеей и решит мою проблему, но не представляется возможным настраивать сторонние виджеты для ее использования (например, «WebView» на Android), поскольку они не дают вам доступа к их фабрикам сокетов и не используют по умолчанию, как и те, которые заданы 'SSLContext.setDefault (...)' :( –

+0

, чтобы решить проблему веб-просмотра, вы можете очень хорошо использовать JavaScriptInterface для реализации схемы аутентификации по вашему выбору или даже настраиваемого протокола, который вы захват в WebViewClient, например encrypted: // mystuff – rupps

1

Вы можете связать его с 127.0.0.1, [1], который предотвращает даже процесс за пределами локального хоста даже от его просмотра. Но любой процесс в localhost может подключиться к нему. Это то, для чего он нужен. Если вы хотите ограничить этот процесс до определенными процессами, вам придется реализовать шаг аутентификации в вашем протоколе.

Трудно понять почему. Если вы не можете доверять другим процессам в localhost, у вас есть довольно большая проблема в целом, а не только здесь.

[1] Или действительно 127.0.0.x, где 1 <= x <= 254. Использование неясного номера, такого как 200, может помочь в неизвестности, но оно по-прежнему не очень безопасно.

0

От Android Security Tips:

Мы уже видели, некоторые приложения используют сетевые порты LOCALHOST для чувствительных IPC. Мы отговариваем этот подход, поскольку эти интерфейсы доступны другим приложениям на устройстве. Вместо этого вы должны использовать механизм IPC для Android, где возможна аутентификация, например, с помощью службы. (Еще хуже, чем использование loopback для привязки к INADDR_ANY, с тех пор ваше приложение может получать запросы из любой точки.)

+0

Спасибо mikkokoo! Жаль, что Google не добавил способ настройки фабрики сокетов для веб-просмотров ... это просто решит мою проблему. Возможно, они делают это в будущей версии Android. –