webSocket ws client-handling auf dem Server ??

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • webSocket ws client-handling auf dem Server ??

    Hallöchen,

    meine Anfänge mit ws schreiten langsam voran, aktuell könnte ich etwas Hilfe beim send()-Wrapper brauchen und das grundlegende Händeln der Clients.


    1) Ich wollte eine emit()-Funktion schreiben damit ich später meinen alten vorhandenen Server übernehmen kann, es scheint aber schon eine emit() zu geben und zu überschreiben weiß ich nicht ob es Sinnvoll ist und zu einem hat es zu Fehlern geführt, da diese Funktion automatisch beim connecten und verlassen ausgeführt wird :( Hier mein Beispiel (myemit()

    JavaScript-Quellcode

    1. server.on('connection', function connection(client){
    2. console.log('client is validated & connected');
    3. // incoming data
    4. client.on('message', (data) => {
    5. data = JSON.parse(data);
    6. // später hier CSRF-Token validieren + spam/berechtigungen prüfen etc.
    7. app[data.shift()].apply(this, data);
    8. });
    9. // outgoing data
    10. client.myemit = function(){
    11. console.log('emit');
    12. client.send(JSON.stringify(Object.values(arguments))); // CSRF-Token anhängen
    13. }
    14. client.myemit('test', {data: 'here'});
    15. client.myemit('test', 'Hello World');
    16. });
    Alles anzeigen
    Naja gut im Notfall nehme ich nen neuen Namen und ersetzte alten Code mit der Suchen & Ersetzten-Funktion.


    2) Bei socket.io erhält jeder client eine eindeutige ID, über diese ID kann man emits() auch außerhalb verwenden:

    JavaScript-Quellcode

    1. io.of(this.nsp).connected[socket.id].emit('auth', {e:'reLogged'})
    Nun wäre es an der Zeit wieder ähnliches zu realisieren. Das Problem das ich habe ist, WS wird ja irgendwo bereits die einzelnen Klienten ablegen, sonst wäre die Kommunikation ja nicht gewährleistet. Nun möchte ich natürlich nicht hergehen und den Klient einfach in ein eigenes Objekt ablegen (doppelte speicherung). Daher stellt sich mir die Frage wo sind die Klienten und wie gehe ich das am besten an? Möchte ja später nur dessen ID in Räume und co zuweisen und nicht das ganze Objekt.


    3) Grundlegende Server-Struktur. Etwas das mich bei socket.io gestört hat ist, das im Grunde jeder Klient den Server beinhaltet (wenn ich mich nicht irre):

    JavaScript-Quellcode

    1. /** Server */
    2. app.of(settings.lobby.nsp).on('connection', function(client){ // run server
    3. /** connection handling */
    4. lobby.onConnect(client, false); // add new socket to lobby, this will authorize with cookie/session-ID
    5. client.on('loggedin', function(){ lobby.onConnect(client, true); }); // this for reAuth (if default auth failed will this be called)
    6. client.on('logout', function(){
    7. console.log('user has clicked to logout');
    8. lobby.deleteSession(client.uid, client.id, 'app');
    9. }); // user has clicked to logout
    10. client.on('disconnect', function(){ lobby.disconnect(client.uid, client.id, client.isMember); });
    11. /** track each call of this user */
    12. var fetchOn = client.on;
    13. client.on = function(name, func){
    14. fetchOn.call(this, name, function(){ // var name can not be changed!!!
    15. // check is session expired
    16. if( lobby.isExpired(client.uid) ){ console.log('expired on fetch call', name); return false; }
    17. // spam check - defined emits will not raise the spameScore
    18. if( lobby.asOpt.freeEmits.indexOf(name) == -1 && lobby.spamProtector(name, ((lobby.asOpt.punishDublicates) === true ? JSON.stringify(arguments) : false), client.uid) === true ){
    19. func.apply(this, arguments);
    20. }else{
    21. func.apply(this, arguments);
    22. }
    23. });
    24. };
    25. /** admin emits */
    26. client.on('admin', function(req){
    27. // stuff here
    28. });
    29. /** user upload handling */
    30. client.on('uh', function(req){
    31. // stuff here
    32. });
    33. /** contact interaction */
    34. client.on('contact', function(data){
    35. // stuff here
    36. });
    37. /** header searchbar */
    38. client.on('searchbar',function(data){
    39. // stuff here
    40. });
    41. /** emit handlings */
    42. client.on('testEmit',function(data){
    43. // stuff here
    44. });
    45. });
    Alles anzeigen
    Auf Grund der clinet.on()-Funktion, wird doch jede Funktion innerhalb der Klient-instanz abgelegt und dadurch steigt die Auslastung im Arbeitsspeicher dann exponentiell an...
    Womit ich eigentlich richtig liegen müsste, da ich jetzt bei WS einen anderen Ansatz gehe wo ebenfalls eine on()-Funktion verwendet wird, diese jedoch alle Funktionen nur einmal bei Serverstart der Applikation hinzufügt und nicht jedem einzelnen User, hier mal mein derzeitiger Server (Ansatz):

    JavaScript-Quellcode

    1. const fs = require('fs');
    2. const https = require('https');
    3. const webSocket = require('ws');
    4. // meine Server Funktionen die später alles mögliche handhaben
    5. function WPOAPP(){
    6. var that = this; // refferenz for async functions
    7. // var ws = **; //
    8. this.on = function(name, func){ this[name] = func; } // register new functions
    9. this.validateUser = function(){
    10. // console.log( arguments );
    11. // validierung mit cookie und co wird hier noch folgen (falls möglich)
    12. return true;
    13. }
    14. }
    15. const app = new WPOAPP();
    16. const host = new https.createServer({
    17. cert: fs.readFileSync('/srv/mm/node_modules/wpocms/server.crt'),
    18. key: fs.readFileSync('/srv/mm/node_modules/wpocms/server.key')
    19. }).listen(8080);
    20. const server = new webSocket.Server({
    21. server: host,
    22. verifyClient: app.validateUser,
    23. perMessageDeflate: {
    24. zlibDeflateOptions: { // See zlib defaults.
    25. chunkSize: 1024,
    26. memLevel: 7,
    27. level: 3,
    28. },
    29. zlibInflateOptions: {
    30. chunkSize: 10 * 1024
    31. },
    32. // Other options settable:
    33. clientNoContextTakeover: true, // Defaults to negotiated value.
    34. serverNoContextTakeover: true, // Defaults to negotiated value.
    35. clientMaxWindowBits: 10, // Defaults to negotiated value.
    36. serverMaxWindowBits: 10, // Defaults to negotiated value.
    37. // Below options specified as default values.
    38. concurrencyLimit: 10, // Limits zlib concurrency for perf.
    39. threshold: 1024, // Size (in bytes) below which messages should not be compressed.
    40. }
    41. });
    42. server.on('connection', function connection(client){
    43. console.log('client is validated & connected');
    44. // incoming data
    45. client.on('message', (data) => {
    46. data = JSON.parse(data);
    47. // später hier CSRF-Token validieren + spam/berechtigungen prüfen etc.
    48. app[data.shift()].apply(this, data);
    49. });
    50. // outgoing data
    51. client.myemit = function(){
    52. console.log('emit');
    53. client.send(JSON.stringify(Object.values(arguments))); // CSRF-Token anhängen
    54. }
    55. client.myemit('test', {data: 'here'});
    56. client.myemit('test', 'Hello World');
    57. });
    58. // app specifical functions | alle Funktionen die hier folgen werdem dem Server einmal hinzugefügt und nicht jedem Klient
    59. // heißt natürlich man müsste später immer die Klinet-ID übermitteln um emits sendne zu können
    60. app.on('message', (message, world = 'no') => {
    61. console.log('received:', typeof message, typeof world);
    62. console.log('received:', message, world);
    63. });
    64. console.log('juhu server running');
    65. setInterval(function(){ console.log('Juhu Server running'); }, 60000);
    Alles anzeigen
    Nun bin ich gespannt auf eure Hilfe und Feedbacks :)

    Klar es fehlt noch die richtige Validierung beim Verbindungsaufbau, wollte aber erst mal die jetzigen Probleme klären um zu sehen ob ich überhaupt an meine Ziele komme.
    Ich habe aber schon die client instanzen in Dateien schreiben lassen und gegenüber socket.io ist es jetzt deutlich weniger =)


    MfG: Paykoman

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Paykoman ()

  • Paykoman schrieb:

    Ich wollte eine emit()-Funktion schreiben damit ich später meinen alten vorhandenen Server übernehmen kann, es scheint aber schon eine emit() zu geben und zu überschreiben weiß ich nicht ob es Sinnvoll ist und zu einem hat es zu Fehlern geführt, da diese Funktion automatisch beim connecten und verlassen ausgeführt wird
    emit() wird schon vom EventEmitter von Node verwendet. Etwas ungünstig, dass auch Socket.io diesen Namen verwendet. Ich würde da doch eher send() und broadcast() verwenden.

    Ein Klientwrapper könnte so aussehen:

    JavaScript-Quellcode

    1. const EventEmitter = require('events')
    2. class ClientWrapper extends EventEmitter {
    3. constructor(client, id) {
    4. super()
    5. this.id = id
    6. this.ws = client
    7. this.ws.on('message', message => {
    8. const { eventName, payload } = JSON.parse(message)
    9. this.emit(eventName, payload)
    10. this.emit('message', message)
    11. })
    12. }
    13. send(eventName, payload) {
    14. this.ws.send(JSON.stringify(eventName, payload))
    15. }
    16. }
    17. server.on('connection', function connection(ws) {
    18. const client = new ClientWrapper(ws, 'meine id')
    19. ws.client = client // hilft beim broadcast und beim externen suchen
    20. client.on('test', data => {
    21. app[data.shift()].apply(this, data)
    22. })
    23. client.send('test', { data: 'here' })
    24. client.send('test', 'Hello World')
    25. })
    Alles anzeigen


    Paykoman schrieb:

    Bei socket.io erhält jeder client eine eindeutige ID, über diese ID kann man emits() auch außerhalb verwenden:
    Nun wäre es an der Zeit wieder ähnliches zu realisieren. Das Problem das ich habe ist, WS wird ja irgendwo bereits die einzelnen Klienten ablegen, sonst wäre die Kommunikation ja nicht gewährleistet. Nun möchte ich natürlich nicht hergehen und den Klient einfach in ein eigenes Objekt ablegen (doppelte speicherung). Daher stellt sich mir die Frage wo sind die Klienten und wie gehe ich das am besten an? Möchte ja später nur dessen ID in Räume und co zuweisen und nicht das ganze Objekt.
    Bei ws liegen die Klienten im server.clients-Array. Wenn du meinen ClientWrapper von oben verwendest, kannst du einen einzelnen Klienten z.B. so über seine Id finden:

    JavaScript-Quellcode

    1. function findClient(id) {
    2. return server.clients.find(ws => ws.client.id === id)
    3. }


    Paykoman schrieb:

    Auf Grund der clinet.on()-Funktion, wird doch jede Funktion innerhalb der Klient-instanz abgelegt und dadurch steigt die Auslastung im Arbeitsspeicher dann exponentiell an...
    Das lässt sich umgehen. Anstelle im connect-Event die Listener alle mit neuen einzelnen
    anonymen Funktionen zu versehen, kann man die Listenerfunktionen auch außerhalb des Scopes definieren und so jedem Klienten aus die selben Funktionen verweisen lassen (keine Kopien mehr):

    JavaScript-Quellcode

    1. const handler = {
    2. admin(reg) {
    3. // stuff here
    4. },
    5. uh(reg) {
    6. // stuff here
    7. },
    8. contact(reg) {
    9. // stuff here
    10. },
    11. searchbar(reg) {
    12. // stuff here
    13. },
    14. testEmit(reg) {
    15. // stuff here
    16. },
    17. }
    18. app.on('connection', function(client) {
    19. /** admin emits */
    20. client.on('admin', handler.admin)
    21. /** user upload handling */
    22. client.on('uh', handler.uh)
    23. /** contact interaction */
    24. client.on('contact', handler.contact)
    25. /** header searchbar */
    26. client.on('searchbar', handler.searchbar)
    27. /** emit handlings */
    28. client.on('testEmit', handler.testEmit)
    29. })
    Alles anzeigen
    Dadurch wird dein Memory-footprint deutlich reduziert.
  • Puhhh, puhhh, kompliziert :D

    Also wenn ich es richtig verstehe, wäre dein Ansatz für jeden Client eine neue Instanz des clientWrappers auszuführen, innerhalb dieser Instanz wird die ID gesetzt als auch das client-Objekt abgelegt. Was ich nicht ganz verstehe, weil es ja alles clientintern bleibt, da jede Verbindung ihre eigene Instanz öffnet und es kein übergeordnete Auflistung gibt in dessen die verscheidenen Instanzen gespeichert wären um mit dessen arbeiten zu können.

    Aber das verbindungsobjekt (client bzw. jetzt ws) wird dort abgelegt, ich gehe also davon aus das man da garnicht drum rum kommt hm?
    Wie gesagt finde es etwas verwirrend, ich schreib noch mal etwas prozeduraler was ich meinte...

    JavaScript-Quellcode

    1. var clientHandler = {};
    2. server.on('connection', function connection(client){
    3. client.id = getUniID();
    4. clientHandler[client.id] = client;
    5. });


    Das ist in der Tat jetzt mal simple ausgedrückt würde aber der Funktionsweise nahe kommen wie es gebraucht wird.
    Jeder Client der sich anmeldet wird dem Objekt hinzugefügt, und jeder client kann einfach mit clientHandler[clientID].send(); dem anderen etwas zusenden.
    Die Wrapper, suchfunktionen etc. sind klar und müssen natürlich drum rum gebaut werden.

    Dies wollte ich so jetzt nicht unbedingt machen weil das Objekt von client sowohl im Server als auch im clientHandler doppelt gespeichert würde, was bei deiner Variante aber ja auch der Fall wäre (oder ist des wurscht weil JS es eh nur als Refferenz/Bezugsquelle ablegt und die Daten nicht wirklich doppelt existieren?).

    Als nächstes würde ich das innerhalb meiner const app = new WPOAPP(); einbauen, weil das mein client übergreiffender wrapper ist.
    Sprich dort speichere ich später user bezogene Daten, Räume in dessen dann die cleint-ID rein soll und natürlich kommen auch die Wrapper da rein die dann alle in einem Raum emiten u.s.w.


    Noch mal Beispiel (sturerweise mit meinem client statt ws xD :(

    JavaScript-Quellcode

    1. const fs = require('fs');
    2. const https = require('https');
    3. const webSocket = require('ws');
    4. function WPOAPP(){
    5. var that = this; // refferenc for async functions
    6. this.clients = {};
    7. this.on = function(name, func){ this[name] = func; } // register new functions
    8. this.clientParser = function(client){
    9. var id = Math.floor(Math.random() * (99999999 - 999 + 1)) + 999; // Beispiel...
    10. this.clients[id] = client;
    11. return id;
    12. }
    13. this.validateUser = function(){
    14. // console.log( arguments );
    15. // validierung mit cookie und co wird hier noch folgen
    16. return true;
    17. }
    18. this.sendToClient = function(id, eventName, payload){
    19. // irgend eine Funktion gibt den auftrag an eine
    20. // client.id etwas zu senden
    21. this.clients[id].send(JSON.stringify([eventName, payload]));
    22. }
    23. }
    24. const app = new WPOAPP();
    25. const host = new https.createServer({
    26. cert: fs.readFileSync('/srv/mm/node_modules/wpocms/server.crt'),
    27. key: fs.readFileSync('/srv/mm/node_modules/wpocms/server.key')
    28. }).listen(8080);
    29. const server = new webSocket.Server({
    30. server: host,
    31. verifyClient: app.validateUser
    32. });
    33. server.on('connection', function connection(client){
    34. client.id = app.clientParser(client); // der umständlichere Weg wenn client.id nicht in der validate funktion zugewiesen werden kann
    35. console.log('client is validated & connected', client.id);
    36. // incoming data
    37. client.on('message', (data) => {
    38. data = JSON.parse(data);
    39. // später hier CSRF-Token validieren + spam/berechtigungen prüfen etc.
    40. app[data.shift()].apply(this, data);
    41. app.sendToClient(client.id, 'test', 'wurde empfangen');
    42. });
    43. // outgoing data
    44. client.myemit = function(){
    45. console.log('emit');
    46. client.send(JSON.stringify(Object.values(arguments))); // CSRF-Token anhängen
    47. }
    48. });
    49. // app specifical functions
    50. app.on('message', (message, world = 'no') => {
    51. console.log('received:', typeof message, typeof world);
    52. console.log('received:', message, world);
    53. });
    Alles anzeigen
    Das ist wieder recht prozedural aber ohne weiteres Fachwissen und Co in webSocket, würde ich das jetzt so umsetzen xD
    Aufmerksam wollte ich eigentlich auf die client.ID im überall verfügbaren app machen die mehr oder weniger den Client enthalten muss.
    Mein Server ist schon recht komplex, mit diversen async Funktionen oder das eben gar erst ein externer Server angesprochen werden muss, in diesen Fällen habe ich immer die client.ID oder mit an den externen Server übersendet und lasse mir diese wieder mit zurück geben, so das einfach mit app.clients[ID].send() der Initiator angesprochen werden kann. Ich sehe nicht wie ich das mit deinem Vorschlag hinbekomme (obige Gründe, kann ja nicht auf die Instanz zugreifen).
    Klar dein Beispiel enthielt ne Suche, die scheinbar das ganze Klient-Objekt zurück gibt aber das bissl too much & boring.

    Entschuldige falls ich da gerade etwas schwer fällig bin, vllt. wärs einfacher zuverstehen hättest nen Beispiel in meine app Funktion reingebastelt.

    LG: Paykoman

    ::EDIT::
    So habe diverses noch gelöst und angefangen die alten Funktionen zu übernehmen, morgenfrüh poste ich noch mal die gesamte neue Server-Datei da sollte dann noch mal einiges verdeutlicht werden...

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Paykoman ()

  • So, Server steht soweit, auth und diverse grundlegende handlings sind jetzt eingebunden, hier und da herrscht natürlich noch Baustelle aber die Grundfunktionen stehen. Ist entsprechend groß geworden, es empfiehlt sich den Code in ein Editor zu laden wo man die Funktionen zusammenklappen kann (fold all) =)

    Wenn man sich etwas durch gearbeitet hat, sieht man das die eigentliche Client-Instanz jetzt nicht mehr mit den ganzen server-listners gefüllt werden, ich habe jetzt lediglich 1 listner der jeden call empfängt und an eine entsprechende Funktion weiterleitet (diese sorgt dann dafür das die gewünschte Funktion ausgeführt wird und prüft die Herkunft und validiert auf spam).

    Dadurch geht natürlich die Clientinstanz verloren, da ich nicht das gesamte Objekt an jede Funktion übergeben möchte beschränke ich mich auf ID´s und isMember & isAdmin, so kann jeder Listner feststellen welcher clientID/userID etwas anfordert und entsprechend handeln.
    Wenn im Listner keine asynch Funktionen kommen kann einfach das richtige Objekt per return gesendet werden um eine Antwort zu senden (Baustelle) oder eben über app.emit(client.id, eventName, data); (fertig).

    Sollte ich irgend etwas übersehen haben, gerade in punkto Memory-footprint, bin ich natürlich für Verbesserungen sehr dankbar!

    CSRF-technich würde mich interessieren ob hier andere Webseiten ebenfalls eine bestehende Verbindung vorgaukeln und emits im namen des users senden können? Also wie ein CSRF auf eine Webseite eben auf WebSocket.
    Aktuell hängt der client den aktuell gültigen CSRF-Token an jeden emit() an, wodurch der Server hier natürlich aktiv werden kann, wenn aber die connection ausreichend ist zu validieren könnte man dem Server und Traffic das ersparen.

    MfG: Paykoman
    PS: am client muss ich noch diverses fertigstellen, folgt dann aber noch hier.
    PSS: Firerfox stellt zum verrecken keine Verbindung her bzw. bricht sie i.d.R. noch während die Seite geladen wurde ab, Ratlosigkeit!

    Firerfox schrieb:

    Firefox kann keine Verbindung zu dem Server unter wss://www.sample.de:8080 aufbauen.
    Die Verbindung zu wss://www.sample.de:8080 wurde unterbrochen, während die Seite geladen wurde.
    event.error: readyState: 3, bubbles: false; cancelBubble: false; cancelable: false; composed: false; currentTarget: null; defaultPrevented: false; eventPhase: 0
    Dateien
    • app.js

      (31,46 kB, 2 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Paykoman ()

  • Paykoman schrieb:

    Was ich nicht ganz verstehe, weil es ja alles clientintern bleibt, da jede Verbindung ihre eigene Instanz öffnet und es kein übergeordnete Auflistung gibt in dessen die verscheidenen Instanzen gespeichert wären um mit dessen arbeiten zu können.
    Es gibt eine übergeordnete Liste: server.clients


    Paykoman schrieb:

    Dies wollte ich so jetzt nicht unbedingt machen weil das Objekt von client sowohl im Server als auch im clientHandler doppelt gespeichert würde, was bei deiner Variante aber ja auch der Fall wäre (oder ist des wurscht weil JS es eh nur als Refferenz/Bezugsquelle ablegt und die Daten nicht wirklich doppelt existieren?)
    In diesem Fall sind es tatsächlich alles nur Referenzen.


    Paykoman schrieb:

    CSRF-technich würde mich interessieren ob hier andere Webseiten ebenfalls eine bestehende Verbindung vorgaukeln und emits im namen des users senden können? Also wie ein CSRF auf eine Webseite eben auf WebSocket.
    Aktuell hängt der client den aktuell gültigen CSRF-Token an jeden emit() an, wodurch der Server hier natürlich aktiv werden kann, wenn aber die connection ausreichend ist zu validieren könnte man dem Server und Traffic das ersparen.
    Eine Verbindung aus dem nichts gibt es nicht und ein Websocket arbeitet immer nur mit einer bestehenden Verbindung. Wenn du also den Verbindungsaufbau überprüfst, sollte das reichen. Nur der man-in-the-middle kann noch gefährlich werden.

    PS: Wenn ich mal etwas Zeit habe schau ich mir mal deine Datei an. Im Moment ist das aber eher schlecht.
  • Neu

    Lichtjaeger schrieb:

    In diesem Fall sind es tatsächlich alles nur Referenzen
    Dürfte sich in meiner Variante dann ja nicht ändern?

    Lichtjaeger schrieb:

    Nur der man-in-the-middle kann noch gefährlich werden
    Wie, jetzt? Auch bei SSL bzw. wss? Da bringt ja auch der kurzlebige CSRF-Token nichts, da ja in dem Fall der Angreifer eh die Daten frei manipulieren kann.

    Lichtjaeger schrieb:

    Eine Verbindung aus dem nichts gibt es nicht
    Ja das ist schon klar, CSRF erfolgt ja auch nicht aus dem Nichts.
    Hier muss ein Nutzer natürlich bei mir angemeldet sein während er weiter im Internet surft, trifft er auf eine Webseite die davon ausgeht das der User bei mir online ist, so schiebt er dem Nutzer eine HTTP-Anfrage unter die an meine Webseite gerichtet ist, hierbei denkt die Webseite das die Anfrage vom tatsächlichen User kommt, da alle Kookies vorhanden sind und eben auch dessen USER_AGENT.

    Die Frage war/ist ob auf gleicherweise dem Nutzer der ja mit meinem ws-Server verbunden ist ein emit (ws-anfrage) untergeschoben werden kann, ist letztlich ja auch nur ein Protokoll. Denn wenn ja müsste man die emits mit dem CSRF-Token validieren, da dieser als einziges dem Angreifer nicht bekannt ist und der emit() nicht vollständig verarbeitet würde.
  • Neu

    Paykoman schrieb:

    Wie, jetzt? Auch bei SSL bzw. wss?
    Nein, das ist ja genau dafür da. Ich hab nur gemeint, dass CSRF alleine nicht gegen man-in-the-middle Angriffe schützt. Ganz allgemein gesprochen.


    Paykoman schrieb:

    Die Frage war/ist ob auf gleicherweise dem Nutzer der ja mit meinem ws-Server verbunden ist ein emit (ws-anfrage) untergeschoben werden kann, ist letztlich ja auch nur ein Protokoll. Denn wenn ja müsste man die emits mit dem CSRF-Token validieren, da dieser als einziges dem Angreifer nicht bekannt ist und der emit() nicht vollständig verarbeitet würde.
    Ein Inject der Klientseite wäre möglich. Wenn der Angreifer aber schon auf dem Klienten ist, nutzt auch ein CSRF Token nichts mehr, da es dann ja wieder ausgelesen werden kann.
  • Neu

    Okay... Stimmt schon, der Unterschied ist eben ob es auf dem selben Wege geschieht wie bei dem gefakten http-request, in diesem Falle kann der Angreifer den CSRF-Token nicht mit übersenden, da er nicht als Kookie abgelegt ist, da müsste der Angreifer parallel die Seite auch über XSS hacken um an diesen heran zukommen, was aber eher unwahrscheinlich ist da unter anderem auch CSP eingesetzt wird mit striktem verbot von inline-code.

    Nutzlos wäre er wenn der Angreifer die emit-Funktion auf der Webseite auslösen könnte, da diese ja automatisch den CSRF-Token dem Emit beifügt, aber das sollte denke ich eigentlich eher nicht möglich sein.

    ::EDIT::
    Ich habe die app.js neu hochgeladen, habe den Fehler gefunden warum FF sich nicht verbinden wollte und das perMessageDeflate Objekt aus der initialisierung einer neuen Websocket-instanz entfernt. FirerFox gibt mir aber jetzt immer unmittelbar beim laden des Seite ein disconnect, entweder 10001 oder 1005, warum auch immer, die Serververbindung steht aber und emits werden hin und her gesendet :D

    Quellcode

    1. connection lost: 1001 socket.client.js:25:9
    2. Opened connection socket.client.js:7:9
    3. test empfangen: erfolgreich als string string socket.client.js:47:5

    JavaScript-Quellcode: ws_client.js

    1. window.WebSocket = window.MozWebSocket || window.WebSocket;
    2. const socket = {};
    3. var wsConn;
    4. function connectWebSocket(){
    5. wsConn = new WebSocket('wss://sample.com:8080?foid='+localStorage.getItem('foid'), ['soap', 'xmpp']);
    6. wsConn.onopen = function(){
    7. console.log('Opened connection ');
    8. // kill reAuth cooki per xhr (PHP only) at same time will be set new CSRF Token (new Token after validation is good!)
    9. };
    10. wsConn.onerror = function(event){ console.log('error', event); };
    11. wsConn.onclose = function(event){
    12. console.log('connection lost:', event.code);
    13. if( event.code == 1006 ){
    14. setTimeout(function(){
    15. connectWebSocket();
    16. }, 3000);
    17. }
    18. };
    19. wsConn.onmessage = function(event){
    20. try{
    21. var data = JSON.parse(event.data);
    22. socket[data.shift()].apply(this, data);
    23. // var data = JSON.parse(event.data);
    24. // var listener = client.listeners[data.shift()];
    25. // if (listener) listener(data)
    26. }catch (error){
    27. console.error(error)
    28. }
    29. };
    30. }
    31. socket.on = function(name, func){ socket[name] = func; };
    32. socket.emit = function(){
    33. if(typeof wsConn == 'object' ){
    34. arguments['csrf'] = localStorage.getItem('foid');
    35. wsConn.send(JSON.stringify(Object.values(arguments)));
    36. }
    37. };
    38. if( ('WebSocket' in window) || ('MozWebSocket' in window) ){
    39. connectWebSocket();
    40. window.addEventListener('beforeunload', () => { wsConn.close(); });
    41. }else{
    42. throw('Sorry, no WebSocket support');
    43. }
    44. socket.on('test', (data) => {
    45. console.log('test empfangen:', data, typeof data);
    46. });
    47. setTimeout(function(){
    48. // send data to the server
    49. // socket.emit('message', 'Hello');
    50. socket.emit('message', 'Hello', 'World');
    51. // socket.emit('message', 'Hello', 'World');
    52. // socket.emit('message', 'Hello', 'World');
    53. // setTimeout(function(){ socket.emit('message', 'Hello', 'World'); }, 10000);
    54. // socket.emit('message', { message: 'Hello ' });
    55. }, 2500);
    Alles anzeigen

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von Paykoman ()