Fermer correctement SSLSocket
Je veux mettre en œuvre un proxy SSL en Java. En gros, j'ai ouvert deux sockets browser-proxy
,proxy-server
, et d'exécuter deux threads qui écrirait à proxy-server
ce qu'ils ont lu à partir de browser-proxy
, et vice versa. Chaque thread ressemble à ceci:
while (true) {
nr = in.read(buffer);
if (nr == -1) System.out.println(sockin.toString()+" EOF "+nr);
if (nr == -1) break;
out.write(buffer, 0, nr);
}
sockin.shutdownInput();
sockout.shutdownOutput(); //now the second thread will receive -1 on read
Chaque thread ne fermer la prise d'entrée, de sorte que finalement les deux sockets sont fermés.
Mais que dois-je faire si je veux utiliser un SSLSocket
? Il semble que la shutdownOutput/Input
méthodes ne sont pas pris en charge. Voici l'exception que je reçois.
Exception in thread "Thread-35" java.lang.UnsupportedOperationException: \
The method shutdownInput() is not supported in SSLSocket
at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.shutdownInput(Unknown Source)
Ce que j'ai trouvé est:
try {
while (true) {
nr = in.read(buffer);
if (nr == -1) System.out.println(sockin.toString()+" EOF "+nr);
if (nr == -1) break;
out.write(buffer, 0, nr);
}
//possible race condition if by some mysterious way both threads would get EOF
if (!sockin.isClosed()) sockin.close();
if (!sockout.isClosed()) sockout.close();
} catch (SocketException e) {/*ignore expected "socket closed" exception, */}
Je dois les attraper et de les ignorer fin de l'exception socket à chaque fois que mon socket se termine.
Mes questions sont:
- Si
shutdownInput()
est pas pris en charge, comment ça se fait que je suis un-1
la réponse d'unSSLSocket
. - Est-il une meilleure solution pour mon agonie? Je ne pense pas qu'il y a quelque chose de sain d'esprit, car le thread peut être déjà dans le blocage
read
méthode lorsque les autres marques de filetage lui "je suis fait". Et le seul moyen que je vois pour l'expulser du blocage du thread est par la fermeture de la socket et l'éducation d'un "socket fermée" exception.(Je suppose que vous pourriez utiliser certains impie combinaison de multithread de passage de messages et de données asynchrone lecture pour signaler à l'autre fil de votre travail est fait, mais c'est tellement horrible que j'ai peur de l'Ide du style cop veut venir après moi, juste pour y penser...)
Précisions: je sais que shutdownInput
et shutdownOutput
n'a pas de sens, puisque vous ne pouvez pas avoir un half-duplex connexion TLS, par spec. Mais, comment puis-je mettre fin à une connexion TLS en Java sans se faire une exception?
S'il vous plaît, ne me dites pas shutdownIput
ne fait pas de sens pour TLS. Je sais que, ce n'est pas ce que je demande à. Je me demande ce que je peux utiliser, dans l'ordre de fermer SSLSocket
correctement (d'où le titre, "fermer Correctement SSLSocket".
Oui, en effet, elle déclenche une exception
Exception in thread "Thread-4" java.lang.UnsupportedOperationException: The method shutdownInput() is not supported in SSLSocket
. J'ai supposé que le un bien suffisant pour répondre à ma question, déjà savons pour un fait qui n'est pas pris en charge avec SSL.Pourriez-vous préciser pourquoi "maintenant, le deuxième thread va recevoir -1 sur "lire" à
sockout.shutdownOutput()
? Sans doute, dans votre exemple, in = sockin.getInputStream()
.désolé pour le retard. Comme je l'ai mis en œuvre, il y a deux fils, l'un de lecture à partir de
s
et écrit ce qu'il a obtenu à t
, et de l'autre la lecture de t
et de l'écriture à s
. Lorsque s
retourne EOF
, c'est à dire read -> -1
, je ferme (le flux de sortie d') socket t
, et par la fermeture, je suis en fait ce qui implique EOF
ont atteint. La prochaine read
de t
doit retourner -1
de signal EOF
. (et merci beaucoup pour revenir à ce fil)Je dirais que, dans votre exemple,
sockin.shutdownInput()
est sans doute inutile puisque les expressions du FOLKLORE a déjà été reçues de toute façon. (C'est plus habituel à l'arrêt de la sortie de la première). N'avez-vous pas obtenir une simultanéité problème, même dans votre plaine TCP exemple? Disons que vous arrêter de lire à partir de sockIn
, mais encore de données à lire à partir de sockOut
. En appelant sockIn.close()
presque immédiatement après l'arrêt de la lecture, vous perdez la possibilité d'écrire ce qui peut toujours être lu à partir de sockOut
.OriginalL'auteur Elazar Leibovich | 2011-06-21
Vous devez vous connecter pour publier un commentaire.
C'était ma première (temporairement supprimé) réponse, mais apparemment, c'était pas assez bon, car il était de -2 ed assez rapidement... je suppose que je devrais ajouter plus d'explications.
Il n'est pas possible de fermer la moitié de la connexion SSL/TLS sockets de respecter le protocole TLS, comme spécifié dans le la section sur les alertes de fermeture.
Bien que vous souhaitez fermer seulement la moitié de la connexion (d'entrée ou de sortie via
shutdownInput()
/shutdownOutput()
), le sous-jacent couche TLS doit encore envoyer cetteclose_notify
paquet avant de vraiment arrêter la communication, sinon, il sera considéré comme une attaque par troncature.La solution est assez simple: utiliser uniquement
close()
surSSLSocket
s: il ne s'agit pas de fermer la connexion comme il serait normal de sockets TCP, mais il le fait proprement, selon le protocole SSL/TLS spécification.MODIFIER: des explications Supplémentaires.
La réponse est toujours: utilisation
close()
, vous pouvez aussi avoir besoin de savoir quand il est approprié de le faire à partir du protocole de SSL/TLS.(Juste pour préciser, ce que vous essayez de faire est effectivement un "Man-In-The-Middle" (MITM) proxy. Vous aurez besoin du client doit être configuré pour la confiance du proxy certificat, peut-être comme si c'était le certificat de serveur si c'est sensé se passer de manière transparente. Comment les connexions HTTPS travailler à travers un proxy HTTP est un autre question.)
Dans certains de vos commentaires à votre autre question connexe, j'ai eu l'impression que vous avez pensé que le fait de ne pas retourner
-1
était de "casser le protocole TLS". Ce n'est pas vraiment sur le protocole, mais à propos de l'API: la façon dont les structures de programmation (classes, méthodes, fonctions, ...) vous sont fournis (programmeur) utilisateur de la TLS de la pile pour être en mesure de l'utilisation de TLS.SSLSocket
est simplement une partie d'une API pour fournir aux programmeurs la possibilité d'utiliser SSL/TLS dans une manière similaire à la plaine deSocket
. Le TLS spécification n'est pas parler sur les sockets.Alors que le protocole TLS (et son precessor, SSL) ont été construits dans le but de le rendre possible pour fournir ce type d'abstraction, à la fin de la journée
SSLSocket
est juste que: une abstraction.En ligne avec la programmation orientée objet, les principes de conception,
SSLSocket
hériteSocket
et tente de respecter le plus fidèlement possible le comportement deSocket
. Toutefois, en raison de la façon dont le protocole SSL/TLS fonctionne (et parce qu'uneSSLSocket
efficacement se trouve sur le dessus de la normaleSocket
), il ne peut y avoir une cartographie exacte de toutes les fonctionnalités.En particulier, la zone de transition à partir d'un socket TCP pour un SSL/TLS socket peut pas être modélisé de manière transparente.
Certains choix arbitraires (par exemple, la poignée de main a lieu) doit être fait lors de la conception de la
SSLSocket
classe:c'est un compromis entre ne pas (a) l'exposition de trop de la spécificité de TLS à la
SSLSocket
de l'utilisateur, (b) la prise de la TLS mécanisme de travail, et (c) la cartographie de tous les ce à l'interface existante fournie par la super-classe (Socket
).Ces choix ont inévitablement un impact sur la fonctionnalité de la
SSLSocket
, et c'est pourquoi son Javadoc de l'API de page a une relativement grande quantité de texte.SSLSocket.close()
, en termes d'API, doit se conformer à la description deSocket.close()
.Le
InputStream
/OutputStream
obtenu à partir de laSSLSocket
ne sont pas le même que celui de la sous-jacentes de la plaineSocket
,qui (sauf vous avez converti explicitement) vous risquez de ne pas voir.SSLSocket
est conçu pour être utilisable aussi fidèlement que possible, comme si c'était une plaineSocket
, et laInputStream
que vous obtenez est conçu pour se comporter aussi fidèlement que possible à un fichier de base de flux d'entrée.Ce n'est pas spécifique à Java, par la manière. Même les sockets Unix en C sont utilisés avec un descripteur de fichier et
read()
.Ces abstractions sont pratiques et travaillent la plupart du temps, aussi longtemps que vous savez ce que leurs limites.
Quand il s'agit de
read()
, même en C, la notion deEOF
vient d'une fin-de-fichier de résiliation, mais vous n'êtes pas vraiment à faire avec les fichiers.Le problème avec les sockets TCP est que, tandis que vous pouvez détecter lorsque la partie à distance a choisi de fermer la connexion lors de l'envoi de
FIN
, vous ne pouvez pas détecter qu'il n'a pas, si ce n'est pas envoyer quoi que ce soit.Lors de la lecture de rien à partir d'une prise, il n'y a aucun moyen de faire la différence entre un inactif et une coupure de connexion.
En tant que tel, quand il s'agit de la programmation réseau, en s'appuyant sur la lecture de la
-1
de laInputStream
si bien, mais vous ne comptez jamais exclusivement sur cela, sinon vous pourriez vous retrouver avec des inédits, des connexions inactives.Alors qu'il est "poli" pour un tiers à près de la moitié de la connexion TCP correctement (d'une manière telle que la partie éloignée lit
-1
sur sonInputStream
ou quelque chose d'équivalent, comme décrit dans Ordonnée Contre Avortée de Connexion de sortie en Java), la manipulation de ce cas n'est pas suffisante.C'est pourquoi les protocoles sur le dessus de TCP sont généralement conçue pour donner une indication, quand ils ont terminé l'envoi de données: par exemple,
SMTP envoie
QUIT
(et a des terminateurs), HTTP 1.1 utiliseContent-Length
ou fragments de codage.(En passant, si vous n'êtes pas satisfait avec l'abstraction fournie par
SSLSocket
, essayez d'utiliserSSLEngine
directement. Il est susceptible d'être plus difficile, et cela ne va pas changer ce que le TLS spécification dit à propos de l'envoi declose_notify
.)En général avec le protocole TCP, vous devriez savoir, à l'application du protocole de niveau de, arrêt de l'envoi et de réception de données (pour éviter les inédits des connexions et/ou en s'appuyant sur les erreurs de timeout).
Cette phrase dans le TLS cahier des charges fait ce qui est généralement une bonne pratique, une plus forte exigence quand il s'agit de TLS:
"Il est nécessaire que l'autre partie de répondre avec un close_notify d'alerte qui lui est propre et fermer la connexion immédiatement en rejetant toute attente écrit."
Vous devrez synchroniser en quelque sorte, par l'application du protocole, ou de la partie à distance peut encore avoir quelque chose à écrire (surtout si vous êtes en permettant pipeline de requêtes/réponses).
Si le proxy que vous écrivez est d'intercepter les connexions HTTPS (MITM), vous pouvez rechercher dans le contenu des requêtes. Même si les requêtes HTTP sont en pipeline, vous pouvez compter le nombre de réponses envoyées par
le serveur cible (et s'attendre quand ils fin, par le Contenu de Longueur, de morceaux de délimiteurs).
Toutefois, vous ne serez pas en mesure d'avoir un purement transparent, générique TLS "interceptor".
TLS est conçu pour assurer le transport entre les deux parties et de ne pas en avoir un dans le milieu.
Alors que la plupart du mécanisme pour réaliser cette protection (en évitant un MITM) se fait via le certificat de serveur, certains autres TLS mécanismes (alerte de fermeture est l'un d'entre eux).
N'oubliez pas que vous êtes effectivement la création de deux groupes distincts les connexions TLS, le fait qu'ils sont difficiles à se confondent en un seul ne devrait pas être surprenant, compte tenu de l'objectif de TLS.
SSLSocket.close()
est la bonne façon de fermer uneSSLSocket
, mais le protocole d'application sera également vous aider à déterminer quand il est approprié de le faire.close
, mais l'autre extrémité throws exception, au lieu de proprement retour-1
à lire. Est-il possible de faire de Java retour-1
lors de la fermeture de la connexion TLS? Oui, il est, il le fait quand je suis avec un non-Java entité. Comment puis-je imiter ce comportement?Je viens de réalisé cette section de la RFC 2818 devrait également être pertinent: "Parce que TLS est inconscient de requête/réponse HTTP limites, il est nécessaire d'examiner les données HTTP lui-même (en particulier le Contenu de l'en-tête de Longueur) afin de déterminer si la troncature s'est produite à l'intérieur d'un message ou entre les messages."
Salut Bruno, savez-vous certains de prêt à l'emploi solution de SSL moteur?
OriginalL'auteur Bruno
SSL sémantique pour fermer les connexions sont différentes de TCP, de sorte que shutdownInput et shutdownOutput n'ont pas vraiment de sens, au moins au niveau de contrôle disponible dans SSLSocket. Le SSLSocket fondamentalement, vous libère de la charge de SSL traitement d'enregistrement et de communication SSL traitement du message. Il gère également la SSL de traitement d'alerte, et une de ces alertes est le close_notify alerte. Voici le texte de la RFC 2246 sur le sens de cette alerte.
Java fournit suicidalists avec une autre API, le SSLEngine API. Ne les touchez pas, il va vous faire mal.
shutdownInput
etshutdownOutput
pour que l'autre côté-1
quand il essaie de lire le flux, au lieu d'une exception?Leibovich Vous devriez appeler SSLSocket.close(). Je ne suis toujours pas clair sur l'endroit où vous êtes l'obtention de l'exception.
OriginalL'auteur James K Polk
Afin de résoudre votre problème, vous devez effectuer les opérations suivantes:
Sur l'autre extrémité de la partie qui lit à partir de la prise recevrez l'-1-longueur de message au lieu d'exception socketexception levée.
OriginalL'auteur cha2lenger