Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Работа с сетью > WebSocket (Java сервер) Какие есть способы?


Автор: ZVano 28.10.2015, 11:59
Прежде всего - мой уровень в Java нулевой. Пришлось заняться в связи с войной браузеров.

Задача: Нужно из браузерного JavaScript вызывать функции *.dll, *.so (ЭЦП, работа с оборудованием, работа с принтером)
Раньше этим занимался JavaApplet, но в связи с отказом содателей браузеров от поддержки NPAPI они перестали работать (в Chrome Java уже не работает, в Mozilla Firefox перестанет работать через год).

Идея решения такова:
1. Написать Java-приложение, которое будет запускаться через JNLS (Java Web Start).
2. Java-приложение должно уметь работать с dll.
3. Java-приложение должно открывать порт для чтения HTTP-трафика (обеспечивать серверную сторону WebSocket).
4. Написать код JavaScript, который будет обращаться к Java-приложению через WebSocket.

Т.е. загрузили Web-страницу, вызвали загрузку JNLP. После этого пуляем JSON через WebSocket и получаем асинхронные ответы.


Вопросы: Как реализовать п3?
Подозреваю что в JDK должно быть готовое решение, но я его не нашел - все примеры используют Tomcat или GlassFish.
Есть рабочий пример UploadServer, который может принимать файлы по HTTP.  Взят отсюда http://www.denvo.ru/pub/programming/upload-server.html и запилен в проект NetBeans 8 (по умолчанию висит на порту 8011).
Но тут прийдется анализировать заголовки, извлекать из "грязного" текста нужное мне тело пакета (данные в формате JSON).
Прошу сориентировать в этом вопросе. 
Может есть простой готовый класс основанный на событиях.
Произошло событие "пишли данные" в параметре data лежит тело пакета, а в параметре headers HTTP заголовки.

Может первичная задача вообще решается не так, как я думаю.

Автор: LSD 28.10.2015, 12:23
Зачем вам вообще веб часть при наличии полноценного десктоп приложения?

Автор: ZVano 28.10.2015, 12:37
Потому что уже написаны мегатонны кода и никто переделывать его не будет. 
Техзадание было на Web-приложение.

Автор: LSD 28.10.2015, 16:57
Disclaimer: то что вы пытаетесь реализовать это извращение с кучей подводных камней (типа как обойти фаервол, где и как смотреть логи и т.п.). И лучше все таки изменить архитектуру, хотя бы показывать приложение внутри https://www.teamdev.com/jxbrowser (или в чем-то подобном).

Если же надо именно реализовать вебсервер, то надо просто взять готовую реализацию вебсервера. Например https://github.com/NanoHttpd/nanohttpd, и написать свои обработчики событий.

Автор: ZVano 28.10.2015, 17:24
Цитата(LSD @  28.10.2015,  16:57 Найти цитируемый пост)
Disclaimer: то что вы пытаетесь реализовать это извращение с кучей подводных камней

Скорее всего я недостаточно понятно описал ситуацию и Вы просто поняли что требуется.
Цитата(LSD @  28.10.2015,  16:57 Найти цитируемый пост)
Если же надо именно реализовать вебсервер

Нужно из JavaScript вызвать функцию dll и получить результат. Все остальное следствие.

Попробую объяснить по другому.

Имеем Web-приложение с серверной частью на PHP+Apache.
Клиенты в браузере набивают некие данные (например платежки или отчет в налоговую).
И вот наступает момент, когда нужно наложить на эти данные цифровую подпись (ЭЦП).
Наложением ЭЦП занимается сертифицированная библиотека в *.dll и *.so файлах.
Операция наложения подписи должна происходить на стороне клиента т.к. приватный ключ у него на флешке и гонять его на Web-сервер нельзя.
Что делать?
Выкрутились использованием Java-апплета, который загружается в браузер клиента и предоставляет возможность коду JavaScript вызывать функции dll.
И тут как снег на голову новость о том, что Java-апплеты скоро перестанут работать.
Вот и приходится искать решение.
Как бы Вы поступили в моем случае? 
Какие есть решения, кроме того чтобы выгружать данные для подписи в файл и подписывать его отдельной софтиной?

И эта проблемма не только у нас. Почти все банки вынуждены ее решать. Посмотрите какой вой подняли в теме https://www.opennet.ru/opennews/art.shtml?num=43117

PS: кроме наложения ЭЦП нужно  и с железками работать (в некоторых модулях).
Java нужна всего в паре-тройке модулей из нескольких сотен.

PPS:
Цитата(LSD @  28.10.2015,  16:57 Найти цитируемый пост)
Например NanoHTTPD, и написать свои обработчики событий

Спасибо. Вроде подходит. Во всяком случае запущеный пример nanohttpd-websocket отработал - страница браузера отправила пакет с данными и получила его же.
Правда, при билде ругается на то, что не пройден тест. Но это уже вопрос в другую тему.
Цитата

NanoHttpd-Project ................................. SUCCESS [5.872s]
NanoHttpd-Core .................................... FAILURE [1:04.785s]
NanoHttpd-Websocket ............................... SKIPPED
------------------------------------------------------------------------
BUILD FAILURE

Автор: LSD 29.10.2015, 14:12
Цитата(ZVano @  28.10.2015,  18:24 Найти цитируемый пост)
И вот наступает момент, когда нужно наложить на эти данные цифровую подпись (ЭЦП).
Наложением ЭЦП занимается сертифицированная библиотека в *.dll и *.so файлах.
Операция наложения подписи должна происходить на стороне клиента т.к. приватный ключ у него на флешке и гонять его на Web-сервер нельзя.
Что делать?

Так это просто ключ на флешке или токен который сам все подписывает?


Цитата(ZVano @  28.10.2015,  18:24 Найти цитируемый пост)
Как бы Вы поступили в моем случае? 

It depends...
- Кто использует приложение - внутренние или внешние клиенты. 
- На каких ОС и браузерах оно используется и можно ли сократить этот круг. 
- Планируется ли дальнейшее активное развитие приложения.

Автор: ZVano 29.10.2015, 16:19
Цитата(LSD @  29.10.2015,  14:12 Найти цитируемый пост)
Так это просто ключ на флешке или токен который сам все подписывает?

Токен. "Кристалл 1" http://eu.iit.com.ua/ и пример JavaApplet http://sign.eu.iit.com.ua/
Не забываем что кроме ЭЦП есть еще обращение к железякам через dll.
Цитата(LSD @  29.10.2015,  14:12 Найти цитируемый пост)
Кто использует приложение - внутренние или внешние клиенты. 

В основном внешние.
Цитата(LSD @  29.10.2015,  14:12 Найти цитируемый пост)
На каких ОС и браузерах оно используется и можно ли сократить этот круг.

ОС Windows для спецмодулей и любые другие для остального.
Браузеров зоопарк и они забиты в ТЗ.
Цитата(LSD @  29.10.2015,  14:12 Найти цитируемый пост)
Планируется ли дальнейшее активное развитие приложения. 

Я не знаю. Это только руководству известно.

Автор: LSD 30.10.2015, 15:52
В принципе тогда вариантов действительно немного. Или локальный вебсервер или приложение. Мне лично больше нравится вариант с веб браузера внутри Java приложения, т.к.:
1. Тут нет сетевого взаимодействия и нет риска что будет проблемы с сетью из-за фаервола или cross origin request.
2. Диагностика проще, Java приложение может собирать логи свои и вебстраницы и любую дополнительную информацию.
3. Фиксированная версия браузера.
4. Приложение может предоставлять больше функций чем вебстраничка внутри браузера. Нотификации, работа в офлайне, более продвинутая работа с файлами и т.п.

Автор: ZVano 30.10.2015, 16:39
Цитата(LSD @  30.10.2015,  15:52 Найти цитируемый пост)
 Мне лично больше нравится вариант с веб браузера внутри Java приложения,

А как в этом случае использовать уже существующий код, который крутится на внешнем Web-сервере?
Апплеты будут работать в Java-browser?
С куками он умеет работать?
JavaScriprt работает?
Возможности HTML5 поддерживает?

Автор: LSD 30.10.2015, 17:52
  •  Вы через Java Web Start ставите пользователю приложение. 
  •  Это приложение внутри себя на панели открывает ваш вебсайт. 
  •  У вашего приложения есть контроль над страницей, оно может слушать события, экспортировать некие функции для JS и самостоятельно вызывать JS функции. Есть полный контроль над DOM.

Вопрос только в том какую использовать реализацию. 
  •  Есть https://www.teamdev.com/jxbrowser это полноценный Chromium (ну может с небольшой задержкой), но он платный и стоит не мало. 
  •  Есть http://djproject.sourceforge.net/ns/ позволяет показывать браузер внутри Swing приложения и взаимодействовать с ним. Если я правильно понял, то он использует https://developer.mozilla.org/ru/docs/XULRunner, считай это тот же Firefox.
  •  В JavaFX есть http://docs.oracle.com/javafx/2/webview/jfxpub-webview.htm, но там могут быть проблемы с совместимостью.
  •  Есть https://github.com/oswetto/Loboevolution реализация HTML движка на Java, опять вопросы по совместимости.
Я их распределил в том порядке, в котором сам стал бы их рассматривать.

Автор: ZVano 30.10.2015, 18:21
LSD, спасибо. 
Буду читать и щупать. Есть еще год до момента "П...ц" (извините за мой французский smile )

Автор: Sajtran 31.10.2015, 15:24
мда, проблема действительно
доступ к локали компа всё больше обрывается через WEB
плагинами только к кажому браузеру отдельно если и это не перекроют
без вариантов, кроме как писать на старый добрый десктоп

Этот ответ добавлен с нового Винграда - http://ru.vingrad.com/WebSocket-(Java-server)-Kakiye-est-sposoby-id56308e94ae2015ee118b4567#findElement_E7045_5634b309ae2015f372887414_0

Автор: ZVano 6.6.2016, 16:33
Внимание! Не тратьте время на тупиковую ветвь.
Этот подход не будет работать, если Ваш Web-ресурс (с которого запускается JNLP) находится под HTTPSом.
Браузер будет блокировать все HTTP, HTTPS, WS и WSS запросы к ресурсу с self-signed сертификатом. Нормальный сертификат для localhost Вы не получите даже за деньги. Вы никак не обойдете это ограничение
Т.е. Вы не сможете присоединиться из JAVA-script к локальному  WebApi-сервису на Java.
Правда, можно руками добавить сертификат в список доверенных в браузере - тогда будет работать (но это совсем не феншуйно).

Если же Ваш Web-ресурс работает по HTTP, то подход работоспособен и весьма удобен в использовании.

PS: Безусловно блокируются фоновые запросы (выводится ошибка в консоль браузера).
Если же ссылку ввести в поле URL браузера, то он(браузер) выдаст страницу с предупреждением и даст возможность добавить сертификат в список доверенных.

Автор: LSD 7.6.2016, 13:01
Цитата(ZVano @  6.6.2016,  17:33 Найти цитируемый пост)
Нормальный сертификат для localhost Вы не получите даже за деньги. Вы никак не обойдете это ограничение

А кто мешает в hosts прописать 
Код

my-site.com 127.0.0.1

?

Автор: ZVano 7.6.2016, 14:33
Цитата(LSD @  7.6.2016,  12:01 Найти цитируемый пост)
А кто мешает в hosts прописать 

Никто не мешает. 
Но это снова изменения руками. Причем нужно обладать соответствующими правами.
Когда я писал "Вы никак не обойдете это ограничение" подразумевалось что решение не будет работать без ручного вмешательства. (Другое решение этой проблемы - написать в инструкции пользователя "Наберите в строке URL значение https://127.0.0.1:2016 и примите сертификат, который вам предложат со страшными предупреждениями") 
Представьте себе ситуацию - пользователям https://forum.vingrad.ru нужно добавить строчку в hosts чтобы зайти на сайт. Много было бы таких отважных? Причем тут собрались умные люди.

Автор: LSD 7.6.2016, 15:14
Я думал это для тестов нужно. 
А зачем нужно JavaScript-у соединяться с localhost? Да еще обязательно по HTTPS? От каких таких атак предполагается защищаться HTTPS-ом?

Автор: ZVano 7.6.2016, 15:27
Цитата(LSD @  7.6.2016,  14:14 Найти цитируемый пост)
А зачем нужно JavaScript-у соединяться с localhost? 

Основной сайт на HTTPSе (Apache+PHP >> HTML+JavaScript).
Ему нужно выполнять функции, которыми раньше занимался JavaApplet (сейчас апплеты не работают).
Для этого на Java сделана отдельная приблуда. Она запускается на том же компьютере, где работает браузер.
JavaScript обращается к ней, а она решает задачи, которые невозможно сделать средствами JavaScript.
http://iit.com.ua/download/productfiles/EUSignAgentD.pdf См. Рисунок 1.1
Цитата(LSD @  7.6.2016,  14:14 Найти цитируемый пост)
Да еще обязательно по HTTPS? От каких таких атак предполагается защищаться HTTPS-ом? 

Защищаться не нужно. Просто браузер блокирует HTTP запросы, если страница загружена по HTTPS.
На этом я и погорел. DEV и TEST на HTTP. Поэтому прога прошла тестирование. Выкатили на PROD - не работает.

Автор: LSD 7.6.2016, 17:54
Хочу напомнить, что я говорил в прошлом году:
Цитата(LSD @  30.10.2015,  16:52 Найти цитируемый пост)
В принципе тогда вариантов действительно немного. Или локальный вебсервер или приложение. Мне лично больше нравится вариант с веб браузера внутри Java приложения, т.к.:
1. Тут нет сетевого взаимодействия и нет риска что будет проблемы с сетью из-за фаервола или cross origin request.
2. Диагностика проще, Java приложение может собирать логи свои и вебстраницы и любую дополнительную информацию.
3. Фиксированная версия браузера.
4. Приложение может предоставлять больше функций чем вебстраничка внутри браузера. Нотификации, работа в офлайне, более продвинутая работа с файлами и т.п. 



Что же касается твоей ситуации, то можно попробовать следующее: получить сертификат на некий свой поддомен: local-api.my-site.com, в DNS для этого хоста прописать 127.0.0.1 (так можно делать). Ну и дальше слать запросы на этот хост. 

Но тут есть ГИГАНТСКАЯ проблема: сервер который крутится локально у клиента должен содержать секретный ключ из сертификата. Единственный способ, как-то минимизировать ущерб, это получить от СЦ ключ с правом подписи других ключей. Для каждого клиента генерировать случайный поддомен и уникальный ключ для него, без права подписи и минимальным сроком жизни. Но возможно тут тоже будут грабли которые пока не видны в траве.

Автор: ZVano 8.6.2016, 09:07
Цитата(LSD @  7.6.2016,  16:54 Найти цитируемый пост)
...Хочу напомнить, что я говорил в прошлом году: п1 ...

cross origin то я победил. А вот с SSL... Ну что поделаешь, не знал я.  По незнанию и наступил на грабли. 
Цитата(LSD @  7.6.2016,  16:54 Найти цитируемый пост)
...получить сертификат на некий свой поддомен: local-api.my-site.com, в DNS для этого хоста прописать 127.0.0.1 (так можно делать)... Но тут есть ГИГАНТСКАЯ проблема...

Обговорил этот вопрос с нашим админом. Он сказал решительное нет.
Цитата(LSD @  7.6.2016,  16:54 Найти цитируемый пост)
...получить от СЦ ключ с правом подписи других ключей...

Спасибо за идею. Покумекаем.

В данный момент идем другим путем. А именно, создаем WebSocket на основном сайте. Он будет выступать в роли поседника, к которому будут цепляться браузеры и их вспомогательные утилиты. Таким образом проблемы должны разрешиться.


Автор: LSD 8.8.2016, 16:47
В продолжении темы, https://habrahabr.ru/company/aladdinrd/blog/306920/ люди пошли тем же путем.
Цитата(LSD @  7.6.2016,  18:54 Найти цитируемый пост)
Что же касается твоей ситуации, то можно попробовать следующее: получить сертификат на некий свой поддомен: local-api.my-site.com, в DNS для этого хоста прописать 127.0.0.1 (так можно делать). Ну и дальше слать запросы на этот хост.


Автор: ZVano 16.11.2017, 13:50
Цитата(LSD @  8.8.2016,  15:47 Найти цитируемый пост)
В продолжении темы, вот тут люди пошли тем же путем.

В итоге мы вернулись к первоначальному решению и оно уже год работает нормально (за исключением мути с самоподписными сертификатами, таки не дали мне нормальных).
Сделал так же альтернативный вариант с WS|WSS WebSocket сервером-посредником. Однако посмотрев сколько лишнего трафика генерируется, насколько неустойчивой и сложной в отладке получилась система, отказались от этого решения (хоть оно и рабочее).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)