From 048627b4f9b7af0081367ba41d0aa88d92c83fa1 Mon Sep 17 00:00:00 2001 From: sta Date: Fri, 7 Mar 2014 21:15:55 +0900 Subject: [PATCH] Modified cookies validation, and added origin header validation --- Example2/Echo.cs | 11 --- Example2/Program.cs | 45 ++++++++- Example3/Program.cs | 45 ++++++++- websocket-sharp/Server/WebSocketService.cs | 101 ++++++++++++++++----- websocket-sharp/WebSocket.cs | 29 +++--- 5 files changed, 175 insertions(+), 56 deletions(-) diff --git a/Example2/Echo.cs b/Example2/Echo.cs index 8a5f359c..bc4694ff 100644 --- a/Example2/Echo.cs +++ b/Example2/Echo.cs @@ -16,16 +16,5 @@ namespace Example2 Send (msg); } - - protected override bool ValidateCookies ( - CookieCollection request, CookieCollection response) - { - foreach (Cookie cookie in request) { - cookie.Expired = true; - response.Add (cookie); - } - - return true; - } } } diff --git a/Example2/Program.cs b/Example2/Program.cs index 0f74dcd3..197ad7fc 100644 --- a/Example2/Program.cs +++ b/Example2/Program.cs @@ -41,9 +41,48 @@ namespace Example2 wssv.AddWebSocketService ("/Echo"); wssv.AddWebSocketService ("/Chat"); - //wssv.AddWebSocketService ( - // "/Chat", - // () => new Chat ("Anon#") { Protocol = "chat" }); + + /* With initializing + wssv.AddWebSocketService ( + "/Echo", + () => new Echo () { + Protocol = "echo", + OriginValidator = value => { + Uri origin; + return !value.IsNullOrEmpty () && + Uri.TryCreate (value, UriKind.Absolute, out origin) && + origin.Host == "localhost"; + }, + CookiesValidator = (req, res) => { + foreach (Cookie cookie in req) { + cookie.Expired = true; + res.Add (cookie); + } + + return true; + } + }); + + wssv.AddWebSocketService ( + "/Chat", + () => new Chat ("Anon#") { + Protocol = "chat", + OriginValidator = value => { + Uri origin; + return !value.IsNullOrEmpty () && + Uri.TryCreate (value, UriKind.Absolute, out origin) && + origin.Host == "localhost"; + }, + CookiesValidator = (req, res) => { + foreach (Cookie cookie in req) { + cookie.Expired = true; + res.Add (cookie); + } + + return true; + } + }); + */ wssv.Start (); if (wssv.IsListening) { diff --git a/Example3/Program.cs b/Example3/Program.cs index fce6ed2d..29343a0b 100644 --- a/Example3/Program.cs +++ b/Example3/Program.cs @@ -45,9 +45,48 @@ namespace Example3 _httpsv.AddWebSocketService ("/Echo"); _httpsv.AddWebSocketService ("/Chat"); - //_httpsv.AddWebSocketService ( - // "/Chat", - // () => new Chat ("Anon#") { Protocol = "chat" }); + + /* With initializing + _httpsv.AddWebSocketService ( + "/Echo", + () => new Echo () { + Protocol = "echo", + OriginValidator = value => { + Uri origin; + return !value.IsNullOrEmpty () && + Uri.TryCreate (value, UriKind.Absolute, out origin) && + origin.Host == "localhost"; + }, + CookiesValidator = (req, res) => { + foreach (Cookie cookie in req) { + cookie.Expired = true; + res.Add (cookie); + } + + return true; + } + }); + + _httpsv.AddWebSocketService ( + "/Chat", + () => new Chat ("Anon#") { + Protocol = "chat", + OriginValidator = value => { + Uri origin; + return !value.IsNullOrEmpty () && + Uri.TryCreate (value, UriKind.Absolute, out origin) && + origin.Host == "localhost"; + }, + CookiesValidator = (req, res) => { + foreach (Cookie cookie in req) { + cookie.Expired = true; + res.Add (cookie); + } + + return true; + } + }); + */ _httpsv.Start (); if (_httpsv.IsListening) { diff --git a/websocket-sharp/Server/WebSocketService.cs b/websocket-sharp/Server/WebSocketService.cs index 67a7f4b0..e905bce4 100644 --- a/websocket-sharp/Server/WebSocketService.cs +++ b/websocket-sharp/Server/WebSocketService.cs @@ -45,6 +45,9 @@ namespace WebSocketSharp.Server #region Private Fields private WebSocketContext _context; + private Func + _cookiesValidator; + private Func _originValidator; private string _protocol; private WebSocketSessionManager _sessions; private DateTime _start; @@ -115,6 +118,38 @@ namespace WebSocketSharp.Server } } + /// + /// Gets or sets the delegate called to validate the HTTP cookies included in the WebSocket + /// connection request. + /// + /// + /// The delegate is called when the used in the current session + /// validates the WebSocket connection request. + /// + /// + /// + /// A Func<CookieCollection, CookieCollection, bool> delegate that references + /// the method(s) used to validate the cookies. 1st passed to + /// this delegate contains the cookies to validate, if any. 2nd + /// passed to this delegate receives the cookies to send to the client. + /// + /// + /// This delegate should return true if the cookies are valid; otherwise, false. + /// + /// + /// The default value is , and it does nothing to validate. + /// + /// + public Func CookiesValidator { + get { + return _cookiesValidator; + } + + set { + _cookiesValidator = value; + } + } + /// /// Gets the unique ID of the current session. /// @@ -125,6 +160,38 @@ namespace WebSocketSharp.Server get; private set; } + /// + /// Gets or sets the delegate called to validate the Origin header included in the WebSocket + /// connection request. + /// + /// + /// The delegate is called when the used in the current session + /// validates the WebSocket connection request. + /// + /// + /// + /// A Func<string, bool> delegate that references the method(s) used to validate + /// the origin header. A passed to this delegate represents the value of + /// the origin header to validate, if any. + /// + /// + /// This delegate should return true if the origin header is valid; otherwise, + /// false. + /// + /// + /// The default value is , and it does nothing to validate. + /// + /// + public Func OriginValidator { + get { + return _originValidator; + } + + set { + _originValidator = value; + } + } + /// /// Gets or sets the subprotocol of the used in the current session. /// @@ -192,6 +259,16 @@ namespace WebSocketSharp.Server #region Private Methods + private string checkIfValidConnectionRequest (WebSocketContext context) + { + return _originValidator != null && !_originValidator (context.Origin) + ? "Invalid Origin header." + : _cookiesValidator != null && + !_cookiesValidator (context.CookieCollection, context.WebSocket.CookieCollection) + ? "Invalid Cookies." + : null; + } + private void onClose (object sender, CloseEventArgs e) { if (ID == null) @@ -234,7 +311,7 @@ namespace WebSocketSharp.Server _websocket = context.WebSocket; _websocket.Protocol = _protocol; - _websocket.CookiesValidation = ValidateCookies; + _websocket.CustomHandshakeRequestChecker = checkIfValidConnectionRequest; _websocket.OnOpen += onOpen; _websocket.OnMessage += onMessage; @@ -422,28 +499,6 @@ namespace WebSocketSharp.Server _websocket.SendAsync (stream, length, completed); } - /// - /// Used to validate the HTTP cookies included in the WebSocket connection request. - /// - /// - /// This method is called when the used in the current session - /// validates the WebSocket connection request. - /// - /// - /// true if the cookies are valid; otherwise, false. This method returns - /// true as default. - /// - /// - /// A that contains the cookies to validate. - /// - /// - /// A that receives the cookies to send to the client. - /// - protected virtual bool ValidateCookies (CookieCollection request, CookieCollection response) - { - return true; - } - #endregion } } diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index b48608fb..f1144854 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -75,13 +75,13 @@ namespace WebSocketSharp private CompressionMethod _compression; private WebSocketContext _context; private CookieCollection _cookies; - private Func - _cookiesValidation; private NetworkCredential _credentials; private string _extensions; private AutoResetEvent _exitReceiving; private object _forConn; private object _forSend; + private Func + _handshakeRequestChecker; private volatile Logger _logger; private uint _nonceCount; private string _origin; @@ -192,13 +192,20 @@ namespace WebSocketSharp #region Internal Properties - internal Func CookiesValidation { + internal CookieCollection CookieCollection { get { - return _cookiesValidation; + return _cookies; + } + } + + // As server + internal Func CustomHandshakeRequestChecker { + get { + return _handshakeRequestChecker ?? (context => null); } set { - _cookiesValidation = value; + _handshakeRequestChecker = value; } } @@ -685,9 +692,7 @@ namespace WebSocketSharp ? "Invalid Sec-WebSocket-Key header." : !validateSecWebSocketVersionClientHeader (headers ["Sec-WebSocket-Version"]) ? "Invalid Sec-WebSocket-Version header." - : !validateCookies (context.CookieCollection, _cookies) - ? "Invalid Cookies." - : null; + : CustomHandshakeRequestChecker (context); } // As client @@ -1258,14 +1263,6 @@ namespace WebSocketSharp receive (); } - // As server - private bool validateCookies (CookieCollection request, CookieCollection response) - { - return _cookiesValidation != null - ? _cookiesValidation (request, response) - : true; - } - // As server private bool validateHostHeader (string value) {