Bezpieczna zdalna konsola CLI

Bezpieczna zdalna konsola CLI
KK
  • Rejestracja:około 12 lat
  • Ostatnio:około 11 lat
  • Postów:135
0

Witam,
Piszę sobie aplikację, w której chciałbym mieć możliwość podłączenia się do własnego CLI. Mogę to zrobić albo lokalnie (jest masa bibliotek), albo po nieszyfrowanym socketcie (bezpieczeństwo tego rozwiązania praktycznie nie istnieje), albo "jakoś inaczej". I tutaj mam pytanie. Ma ktoś może jakiś dobry pomysł?

Ogólnie chodzi o to, żeby podłączyć się do aplikacji po TCP i mieć dostęp do własnej, napisanej konsoli (fajnie byłoby podpiąć gotową bibliotekę, ale jeśli się nie da, to trudno). Niestety potrzebne będzie logowanie, więc zwykły socket nie wystarczy - można się podłączyć z wszystkiego (choćby telnet), ale hasełka latałyby bez szyfrowania. Dlatego też próbowałem SSH, ale własny serwer z własną konsolą, to dość karkołomne rozwiązanie.

0

A jak sie polaczysz za pomoca SSL?

KK
  • Rejestracja:około 12 lat
  • Ostatnio:około 11 lat
  • Postów:135
0

Dzięki za zainteresowanie.
Właśnie dlatego myślałem o SSH, ponieważ można użyć jakiegoś zwyczajnego klienta do połączenia/zalogowania. Niestety nie radzę sobie z serwerem wykorzystującym własną konsolę.

0

W sumie nie do konca rozumiem co chcesz zrobic. Co to znaczy 'wlasne CLI'? Chcesz sie za pomoca Twojej aplikacji polaczyc z jakims shellem na serwerze, czy twoja aplikacja ma wbudowana konsole, ktora potrafi sie polaczyc z serwerem i wykonac jakies polecenia?

KK
  • Rejestracja:około 12 lat
  • Ostatnio:około 11 lat
  • Postów:135
0

Jeszcze inaczej. Chciałbym, żeby moja aplikacja miała swoje własne CLI - odpalam aplikację na serwerze, łączę się z innego kompa z tą aplikacją i mam możliwość interakcji z aplikacją poprzez "zdalną linię poleceń".
Najprościej to zrobić po prostu przez sockety TCP. Otwieram port, na output stream wysyłam konsolę (znak zachęty, wyniki wykonywanych operacji), a z input stream pobieram polecenia. Są z tym jednak trzy problemy: konieczność obsłużenia sesji i logowania użytkowników, problemy z uzupełnianiem komand, no i najważniejsze - brak szyfrowania. Z tego ostatniego powodu chciałem zamiast tego wykorzystać SSH, ale niezbyt wiem, jak zmodyfikować jakąś bibliotekę potrafiącą stworzyć serwer SSH w Javie do tego, żeby po zalogowaniu dała mi input/output stream i możliwość dalszej zabawy na włąsną rękę, bez konsoli, np. bashowej, a jeszcze lepiej - żeby dało się to spiąć z jakąś biblioteką, jak java-cli-api, commons-cli, natural-cli, itp.

0

Nie wiem czy jest lib do javy zeby wystartowac serwer ssh, ale moze sprobuj inaczej - moze poczytaj o tulenowaniu przez ssh? Polega to na tym ze wywolujesz komende ssh z parametrami, i ten ssh tworzy taki jakby 'serwer' u ciebie lokalnie. Ty sie w Teojej aplikacji laczysz z tym serwerem, i wszystko co przeslesz do niego leci przez tunel ssh do twojego 'prawdziwego' serwera. Po strone serwera aplikacja chodzi tylko na lokalhoscie, a jak stworzysz tunel ssh to na serwerze on sie polaczy wlasnie z tym localhostem. W ten sposob poza ssh nikt sie nie polaczy z Twoja aplikacja. Takie wywolanie ssh wyglada mniej wiecej tak:

Kopiuj
ssh -L 1234:host:4321

Co oznacza: laczysz sie z 'host' przez ssh, otwierasz lokalnie (na kliencie z ktorego sie laczysz) socket na porcie 1234, kazde polaczenie z tym socketem spowoduje wytworzenie tunelu do serwera 'host', a tam drugi koniec zostanie polaczony z portem 4321 - to bedzie Twoja aplikacja ktora czeka na polaczenia na localhoscie na porcie wlasnie 4321.
Plusy to to ze bezpieczenstwo i szyfrowanie masz za darmo - korzystasz z ssh. Minusy to np. to ze korzystasz z ssh, czyli jestes dosc mocno od tego zalezny. Moim zdaniem warto sie zainteresowac.
Albo jeszcze inaczej - po prostu zrob aplikacje ktora startuje lokalnie i nie wie nic na temat socketow, sieci i bezpieczenstwa - po prostu startujesz ja i mozesz uzywac na twoim kompie. Instalujesz ja na swerwerze, tam gdzie jest tez serwer ssh. Teraz klienckie aplikacje sie lacza ssh z serwerem, i mozesz uruchomic ta aplikacje. Takie 'poor man's tunneling' ;d Ssh mozesz skonfigurowac tak zeby domyslnie startowac twoja aplikacje. To jest najlatwiejsze co im przychodzi do glowy.
W zaleznosci od tego co to za aplikacja i dla kogo, moga to byc bardzo dobre rozwiazania. Przede wszystkim pomijasz wlasnoreczna implementacje bezpieczenstwa, szyfrowania itp co nie jest trywialne. No chyba ze wlasnie chcesz to sam implementowac, to wtedy nie ;d

0

Sory, zle podalem polaczenie, powinno byc:
ssh -L 1234:localhost:4444 host
Czyli: polacz sie z 'host' przez ssh; gdy na kliencie ktos sie polaczy z localhost:1234 to powstanie tunel do host, a tam ssh polaczy sie z localhost:4444. W ten sposob masz laczenie z ssh (np. za pomoca PKI), szyfrowanie (bo tunel ssh jest szyfrowany), nikt sie nie polaczy z aplikacja inaczej niz po localhost, czyli dosc bezpiecznie ;d

KK
  • Rejestracja:około 12 lat
  • Ostatnio:około 11 lat
  • Postów:135
0

Wielkie dzięki
SSH nie jest dla mnie tajemnicą, więc raczej dam radę:).
Nie myślałem o tunelowaniu z prostego powodu - daję człowiekowi apkę spakowaną do paczki linuxowej (taki deb na przykład), a on ją instaluje. Mogę nawet nie dotykać tej maszyny. Właściwie, to da się zrobić taki numer - po instalacji tworzy się skrypt, który przed uruchomieniem mojego programu tworzy tunel SSH lub jakiś dziwny twór typu IPv6inIPv4 dla zmylenia przeciwnika.
Jest jeszcze jedno rozwiązanie - program uruchamia się w screen-ie (jak ktoś nie zna tego programu, to naprawdę polecam poznać), a później można wejść przez SSH na serwer i dopiąć się do screen-a, gdzie czeka CLI aplikacji. NIESTETY... oznacza to też ofiarowanie użytkownikowi dostępu do basha na serwerze, a tego wolałbym uniknąć. I znów jest to problem rozwiązywalny, tylko strasznie okrężną drogą... Zarządzanie uprawnieniami, oddzielny plik z danymi uwierzytelniania użytkownika stworzonego tylko w tym celu, itd.
Aplikacja i tak jest sieciowa, mam już nawet komunikację klient androidowy - serwer J2SE po JSSE (celowo nie użyłem J2EE, np. JBoss-a). Zdalną konsolę też chciałem zrobić "ładne", ale najwyraźniej się nie da.
Cóż.. w ostateczności użyję JSSE i napiszę sobie własnego klienta. Powinno pójść gładko. Jakbym wykombinował coś ładnego, to napiszę tutaj dla potomnych.

Raz jeszcze dzięki za pomoc.

0

No tak, ja myslalem ze to ma byc jakas tylko aplikacja dla ciebie, nie jakis pakiet dla innych osob. Problem JSSE jest taki ze musisz sam wszystko implementowac, no ale jak trzeba...

airborn
  • Rejestracja:ponad 15 lat
  • Ostatnio:prawie 7 lat
  • Postów:274
0

O ile dobrze zrozumiałem, to ten projekt powinien Ci pomóc http://mina.apache.org/sshd-project/index.html

KK
  • Rejestracja:około 12 lat
  • Ostatnio:około 11 lat
  • Postów:135
0

Masz rację - powinien. Problem pojawia się w momencie próby zmuszenia go do użycia takiego 'ShellFactory', który pozwoli przekazywać polecenia wydane zdalnie do programu, a nie do powłoki systemu operacyjnego.

0

Może to głupie, ale może połączenie TCP i same, przesyłane dane szyfrować?

KK
  • Rejestracja:około 12 lat
  • Ostatnio:około 11 lat
  • Postów:135
0

Fajnie, ale to wymaga napisania klienta. Mało ludzi jest w stanie pisać komendy szyfrując je w locie w głowie :). Walczę z przekierowaniem portu z SSH na nie-SSH. Jak skończę, to wrzucę

KK
  • Rejestracja:około 12 lat
  • Ostatnio:około 11 lat
  • Postów:135
0

A więc dla potomnych zdalne CLI nasłuchujące tylko lokalnie i zabezpieczony serwer SSH, który zajmuje się przekierowaniem połączenia na ten CLI:

Serwer nasłuchujący na połączenia od localhosta:

Kopiuj
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.log4j.Logger;


public class ConsoleServer extends Thread {

	private final int port;
	private final int lenghtOfQuere;
	public AtomicBoolean listening;
	private static final Logger log = Logger.getLogger("Konsola zdalna");

	public boolean isListening() {
		return listening.get();
	}

	public void setListening(boolean listening) {
		this.listening.set(listening);
	}

	public ConsoleServer() {

		port = Integer.parseInt(ServerProperties.getProperty("console_port"));
		log.info("Uruchamiam serwer bez szyfrowania na porcie " + port);
		lenghtOfQuere = 100;
		listening = new AtomicBoolean(true);
	}

	@Override
	public void run() {
		ServerSocket serverSocket = null;
		try {
			serverSocket = new ServerSocket(port, lenghtOfQuere, InetAddress.getByName("localhost"));
			while (listening.get()) {
				new RemoteConsoleHandler(serverSocket.accept()).start();
			}

			serverSocket.close();
		} catch (IOException e) {
			log.error("Nie mogę uruchomić serwera z powodu błędu", e);
			try {
				serverSocket.close();
			} catch (Exception ex) {
			}
			CriticalBehaviour.closeOnFatal(ConsoleServer.class, e);
		}

	}
}

Obsługa poleceń:

Kopiuj

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.LinkedHashMap;

import org.apache.log4j.Logger;

public class RemoteConsoleHandler extends Thread {

	private Socket connection = null;
	private static final Logger log = Logger.getLogger("Obsługa konsoli zdalnej");
	private PrintWriter out;
	private BufferedReader in;
	private String prompt;
	private CommandStore commandStore;

	public RemoteConsoleHandler(Socket s) {
		this.connection = s;
		setPrompt("serwer");
		commandStore = new CommandStore();
	}

	private void setPrompt(String prompt) {
		this.prompt = prompt.concat("# ");
	}

	private String getPrompt() {
		return prompt;
	}

	@Override
	public void run() {

		try {
			InetAddress adr = connection.getInetAddress();
			int remotePort = connection.getPort();
			log.debug("Rozpoczynam obsługę połączenia do konsoli zdalnej z adresu " + adr + " oraz portu " + remotePort);

			out = new PrintWriter(connection.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

			out.format("Nacisnij ENTER, aby rozpoczac"); // jeśli użytkownik łączy się telnetem, to pierwszy komunikat zaczyna się od śmieci, więc warto go ominąć

			in.readLine();

			out.format(getPrompt());

			String command = in.readLine();
			if (command != null) {
				while (!command.equalsIgnoreCase("exit")) {
					if (command.length() > 0) {
						log.trace("Użytkownik " + adr.getHostName() + "/" + remotePort + " wydał polecenie: " + command);
						String answer = handleCommand(command);
						send(answer);
					}
					out.format(getPrompt());
					command = in.readLine();
				}
				log.debug("Rozłączam użytkownika połączonego z adresu " + adr + " oraz portu " + remotePort);
			}
			out.close();
			in.close();
			connection.close();
		} catch (NullPointerException e) {
			log.warn("Użytkownik rozłączył się niespodziewanie");
		} catch (Exception e) {
			log.error("Błąd zdalnej konsoli użytkownika", e);
		}
	}

	private String handleCommand(String command) {
		String status = "Nie rozpoznalem polecenia :(";
		if (command.equalsIgnoreCase("help")) {
			commandHelp();
			status = "";
		} else {
			String newStatus = commandStore.execute(command);
			if (newStatus != null && newStatus.length() > 0) {
				status = newStatus;
			}
		}

		return status;
	}


	private void commandHelp() {
		LinkedHashMap<String, String> helpMessage = commandStore.getHelp();
		String value = "Dostepne sa nastepujace polecenia:\n\n";
		for (String key : helpMessage.keySet()) {
			value = value.concat(key + "\n");
			value = value.concat(helpMessage.get(key));
			value = value.concat("\n\n---------\n\n");
		}
		send(value);
	}

	void send(String msg) {
		try {
			if (msg != null && msg.length() > 0) {
				msg = msg.replaceAll("\n", "\n\r");
				log.trace("Wysyłam odpowiedź: \n" + msg);
				out.println(msg);
			}
		} catch (Exception ioException) {
			log.error("Nie mogę wysłać odpowiedzi z powodu błędu", ioException);
		}
	}
}

No i najciekawsze - tunel SSH:

Kopiuj
import java.util.EnumSet;

import org.apache.log4j.Logger;
import org.apache.sshd.SshServer;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.shell.ProcessShellFactory;
import org.apache.sshd.server.shell.ProcessShellFactory.TtyOptions;

public class TunnelSSH implements PasswordAuthenticator {

	private static final Logger log = Logger.getLogger("Tunel SSH dla konsoli zdalnej");

	public void openTunnel() {
		try {
			SshServer sshd = SshServer.setUpDefaultServer();
			sshd.setPort(Integer.parseInt(ServerProperties.getProperty("secure_console_port")));
			sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(ServerProperties.getProperty("local_ssh_keyset_filename")));
			EnumSet<TtyOptions> enumSet = EnumSet.noneOf(TtyOptions.class);
			enumSet.add(TtyOptions.Echo);
			enumSet.add(TtyOptions.ONlCr);
			enumSet.add(TtyOptions.ICrNl);
			sshd.setShellFactory(new ProcessShellFactory(new String[] { "nc", "localhost", ServerProperties.getProperty("console_port") }, enumSet));
			sshd.setPasswordAuthenticator(this);
			sshd.start();
		} catch (Exception e) {
			log.error("Nie mogę uruchomić bezpiecznego przekierowania dla portu konsoli zdalnej", e);

		}

	}

	public boolean authenticate(String userName, String password, ServerSession session) {
		return UserCache.getInstance().checkUser(userName, password);
	}

}

Widziałem podobne wątki bez odpowiedzi, więc liczę, że się przyda.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)