首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SslStream类评审

SslStream类评审
EN

Code Review用户
提问于 2012-10-26 20:01:30
回答 1查看 1.8K关注 0票数 10

我已经为我的客户创建了一个SslStream抽象类,如果需要的话,我希望您为我检查并增强它

SecureStream.cs

代码语言:javascript
复制
using System;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Program.Connections.Packets;
using Program.Core.Misc;

namespace Program.Connections.Network
{
    public abstract class SecureStream
    {
        private static readonly byte[] Buffer = new byte[0x1f80];
        private const string IpAddress = "192.168.1.65";
        private readonly int _port;
        private readonly Socket _socket;
        private SslStream _sslStream;

        public abstract void Receive(byte[] buffer);
        public abstract void Error(Exception e);

        protected SecureStream(int port)
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
            _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
            _port = port;
        }

        public void Connect()
        {
            _socket.BeginConnect(new IPEndPoint(IPAddress.Parse(IpAddress), _port), Authenticate, null);            
        }

        private async void Authenticate(IAsyncResult ar)
        {
            try
            {
                var onCertificateValidationCallBack =
                    new RemoteCertificateValidationCallback(
                        OnCertificateValidation);
                _sslStream = new SslStream(new NetworkStream(_socket, true), false, onCertificateValidationCallBack);

                await _sslStream.AuthenticateAsClientAsync(IpAddress);
                if (!_sslStream.IsAuthenticated) throw new Exception("not^authenticated");

                do
                {
                    var size = await _sslStream.ReadAsync(Buffer, 0, Buffer.Length);
                    if (size == 0) throw new Exception("invalid^size");
                    var buffer = new byte[size];
                    Native.MemoryCopy(Buffer, buffer, (uint)buffer.Length);
                    Receive(buffer);
                    Array.Clear(Buffer, 0, Buffer.Length);

                } while (_sslStream.CanRead);
            }
            catch (Exception e)
            {
                Error(e);
            }
        }

        internal async Task Send(PacketWriter writer)
        {
            var buffer = writer.GetWorkspace();
            await _sslStream.WriteAsync(buffer, 0, buffer.Length);
        }

        private static bool OnCertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
        {
            return true;
        }
    }
}

CoreServer.cs

代码语言:javascript
复制
using System;
using System.Windows.Forms;

namespace Program.Connections.Network
{
    public sealed class CoreServer : SecureStream
    {
        public CoreServer(int p) : base(p) { }

        public override void Receive(byte[] buffer)
        {
            //TODO: Handle The Buffer
        }

        public override void Error(Exception e)
        {
            //TODO: Add Error Writer.
            MessageBox.Show(
                string.Format("Disconnected from the server."),
                string.Format("Connection Error"), MessageBoxButtons.OK,
                MessageBoxIcon.Error);
            Environment.Exit(1);
        }
    }
}

我只需使用

代码语言:javascript
复制
var coreServer = new CoreServer(/*port*/);
coreServer.Connect();
EN

回答 1

Code Review用户

回答已采纳

发布于 2012-10-27 19:53:51

代码语言:javascript
复制
new byte[0x1f80]

我认为在这里使用十进制会更容易读懂。我不明白为什么你的缓冲区是8096字节,通常的大小是2的幂,比如8192。

代码语言:javascript
复制
IpAddress = "192.168.1.65"

这看起来是一个完美的例子,它应该是可配置的,而不是一成不变的。您应该接受构造函数中的IP地址,就像您已经使用端口号一样。

代码语言:javascript
复制
public abstract void Receive(byte[] buffer);
public abstract void Error(Exception e);

我不确定我喜欢在这里使用继承。我认为使用事件或类似的东西在这里会更有意义。

代码语言:javascript
复制
_socket.BeginConnect(…)

我不喜欢您使用旧的异步编程模型,而您可以(在代码的其他部分)使用async-await。不幸的是,Socket不公开await可实现的方法,而是公开有很多方法可以避免

代码语言:javascript
复制
private async void Authenticate(IAsyncResult ar)

我认为Authenticate不是这个方法的好名字,它不仅仅是身份验证。

代码语言:javascript
复制
throw new Exception("not^authenticated")

您不应该抛出Exception,您应该创建一个从Exception派生的自定义类并使用它。而异常信息应该是人类可读的,而不是像你所看到的那样的错误代码。如果您需要区分不同的错误,可以为它们具有不同的异常类型,或者为此向自定义异常添加属性。

代码语言:javascript
复制
if (size == 0) throw new Exception("invalid^size");

ReadAsync()返回0时,它的大小不是无效的,它意味着流的末尾已经到达,因此您应该采取相应的行动。

代码语言:javascript
复制
Native.MemoryCopy(Buffer, buffer, (uint)buffer.Length);

为什么在这里使用自定义内存复制方法?你有什么理由不使用Buffer.BlockCopy()吗?还有,你为什么要在这里复制?您的类似乎只用于有限的用途(因为您有一个恒定的IP地址),所以您不能确保在Receive()返回后没有使用缓冲区,所以根本不必复制吗?

代码语言:javascript
复制
return true;

我不是保安方面的专家,但我认为你至少应该对这里的证书进行一些检查。否则,您的类并不是真正的“安全流”。

代码语言:javascript
复制
MessageBox.Show(…);

你不应该把这样的代码和GUI代码混在一起,它们应该分开。

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/17978

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档