Разрешения сокетов

179

Среда .NET Framework, предоставляет многочисленные классы, помогающие разрабатывать в приложениях безопасный код. Многие из этих классов предлагают основанную на ролях безопасность и криптографию. Среда .NET Framework также дает объекты разрешений доступа к коду, являющиеся компоновочными блоками для защиты от несанкционированного доступа к коду. Они являются фундаментом, гарантирующим управляемому коду безопасность — может выполняться только тот код, который имеет разрешение выполняться в текущем контексте.

Каждое разрешение доступа к коду демонстрирует одно из следующих прав:

Для мира Интернета и особенно для сетевых приложений классы System.Net предоставляют встроенную поддержку аутентификации и разрешений доступа к коду. Среда .NET Framework дает класс SocketPermission, обеспечивающий соблюдение разрешений доступа к коду.

Класс SocketPermission используется для управления правами на установление и принятие соединений, контролирующими доступ к сети через сокеты. Этот класс состоит из спецификации хоста и набора "действий", определяющих способы установления соединений с этим хостом. Он обеспечивает безопасность кода, контролируя значения имени хоста, IP-адреса и транспортного протокола.

Для сокетов C# имеется два способа обеспечить разрешение, поддерживающее безопасность:

Синтаксис императивной безопасности реализует разрешения, создавая новый экземпляр класса SocketPermission, чтобы при выполнении кода запросить конкретное разрешение, например право установить TCP-соединение. Этот способ обычно применяется, когда настройки безопасности изменяются при выполнении приложения. В декларативном синтаксисе используются атрибуты, позволяющие поместить информацию о безопасности в метаданные нашего кода, чтобы клиент, вызывающий код, мог воспользоваться рефлексией и узнать, какие разрешения требуются для кода.

Императивная безопасность

Этот синтаксис для обеспечения безопасности создает новый экземпляр класса SocketPermission. Синтаксис императивной безопасности можно использовать для выполнения требований и переопределений, но не запросов. Прежде чем вызвать соответствующий критерий безопасности, необходимо через конструктор инициализировать состояние класса SocketPermission, чтобы он представлял конкретную форму разрешения, которую вы ищете.

В следующем приложении демонстрируется основное использование класса SocketPermission. Поскольку этот код ведет себя как клиент, до выполнения этой программы нужно запустить приложение SocketServer.cs, созданное ранее:

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Security;
using System.Security.Permissions;

namespace SocketPermissionSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Устанавливаем удаленную точку для сокета
            IPHostEntry ipHost = Dns.GetHostEntry("localhost");
            IPAddress ipAddr = ipHost.AddressList[0];
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

            Socket sender = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            // Настройка разрешений
            SocketPermission permisSocket = new SocketPermission(
                NetworkAccess.Connect, TransportType.Tcp, "localhost",
                SocketPermission.AllPorts);

            permisSocket.Assert();

            try
            {
                // Соединяем сокет с удаленной endPoint, перехватываем все ошибки
                sender.Connect(ipEndPoint);
                Console.WriteLine("Сокет подключен к {0}", sender.RemoteEndPoint.ToString());

                byte[] bytes = new byte[1024];
                byte[] msg = Encoding.UTF8.GetBytes("Простой тест");

                // Отправляем данные через сокет
                int bytesSend = sender.Send(msg);

                // Получаем ответ от удаленного устройства
                int bytesRec = sender.Receive(bytes);

                Console.WriteLine("Текст ответа: {0}",
                    Encoding.UTF8.GetString(bytes, 0, bytesRec));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                if (sender.Connected)
                {
                    // Освобождаем сокет
                    sender.Shutdown(SocketShutdown.Both);
                    sender.Close();
                }
            }
            Console.ReadLine();
        }
    }
}

Приведенный код показывает, как, используя императивный синтаксис, реализовать безопасность доступа к коду. Важность этого кода в данном случае заключается в вызове одного метода класса SocketPermission - Assert(), который указывает, что приложению разрешается давать согласие на запросы соединения от Интернета и местного ресурса.

Декларативная безопасность

Декларативная безопасность использует атрибуты .NET, чтобы поместить информацию о безопасности внутрь метаданных кода. Атрибуты можно поместить на уровне сборки, класса или члена и указать необходимый тип запроса, требования или переопределения. Для использования этого синтаксиса безопасности сначала через декларативный синтаксис нужно инициализировать данные состояния объекта SocketPermissionAttribute, чтобы он представлял форму разрешения, соблюдение которого обеспечивается в коде.

В следующем примере демонстрируется, как обеспечить выполнение разрешения с использованием SocketPermissionAttribute:

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Security;
using System.Security.Permissions;

namespace SocketPermissionSample
{
    class Program
    {
        static void Main(string[] args)
        {
            LegalMethod();
            Console.ReadLine();
        }

        [SocketPermission(SecurityAction.Assert, Access="Connect", 
            Host="localhost", Port="All", Transport="Tcp")]
        public static void LegalMethod()
        {
            Console.WriteLine("Legal Method");

            // Устанавливаем удаленную точку для сокета
            IPHostEntry ipHost = Dns.GetHostEntry("localhost");
            IPAddress ipAddr = ipHost.AddressList[0];
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

            Socket sender = new Socket(ipAddr.AddressFamily, 
                SocketType.Stream, ProtocolType.Tcp);

            try
            {
                // Соединяем сокет с удаленной endPoint
                sender.Connect(ipEndPoint);
                Console.WriteLine("Сокет подключен к {0}", 
                    sender.RemoteEndPoint.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                if (sender.Connected)
                {
                    // Освобождаем сокет
                    sender.Shutdown(SocketShutdown.Both);
                    sender.Close();
                }
            }

        }
    }
}
Декларативная настройка разрешений сокета

По функциональности приведенная выше программа похожа на предыдущую, однако, в последней программе вместо императивной безопасности используется синтаксис декларативной безопасности, т.е. разрешения для сокета задаются в атрибуте SocketPermission.

Пройди тесты
Лучший чат для C# программистов