Socket Permissions



Socket Permissions

One common feature of network applications is the ability to allow or deny access to the application from specific clients on the network. This feature allows the application administrator to provide a basic level of security to keep unwanted customers out of the application.

You can add this functionality to your C# network applications using the SocketPermission and SocketPermissionAttribute classes, found in the System.Net namespace. These classes provide techniques that allow you to control access to and from your C# network applications based on client network addresses. The two classes implement either declarative or imperative security on the Socket object.

Declarative security Defines security attributes within the application using the SocketPermissionAttribute class. This technique uses metadata within the application code to define security restrictions for the application. Each restriction is defined as an attribute, using the SocketPermissionAttribute class to define the attribute properties.

Imperative security Creates a SocketPermission object within the application to control access. With imperative security, you must create a SocketPermission object and assign a list of security permissions to it.

By far, declarative security is the easiest and most-used technique of the two. Imperative security requires creating a new SocketPermission object, and assigning the proper permissions for the proper objects. This technique is more complex than declarative security, and beyond the scope of this chapter. The following section describes how to easily use declarative security in your network programs.

Implementing Declarative Security

Using declarative security in your network applications is simple. All you need is to add a separate attribute line to your source code for each security attribute you want to include.

The attribute line must be formatted properly for the security attribute. The attribute is placed in the application code using square brackets ([]). This is exactly what you saw in Chapter 16, "Remoting," with the [Serializable] attribute.

The SocketPermissionAttribute class properties are defined within the class constructor:

[SocketPermission(SecurityAction act, Access=acc, Host=host,
   Port=port, Transport=trans)]

Each property in the constructor defines an element that is checked for the security attribute. All elements in the attribute must be satisfied for the attribute to take effect. Following are definitions for the five parameters in the class:

The SecurityAction object The SecurityAction object defines the specific security action that is performed by the attribute. Figure lists the possible SecurityAction values. The most common values are SecurityAction.Assert, which allows access to the resource, and SecurityAction.Deny, which denies access to the resource.

Figure: The SecurityAction Members

member

Description

Assert

The object can access the resource even if calls higher in the attributes deny access.

Demand

All calls to this class higher in the stack must have granted the permission.

Deny

The ability to access the resource specified is denied.

InheritanceDemand

The derived class inheriting this class is required to have been granted permission.

LinkDemand

The immediate caller is required to have been granted permission.

PermitOnly

Only the resources specified in this action can be accessed.

RequestMinimum

The request for the minimum permissions required for the code to run.

RequestOptional

The request for additional permissions that are optional.

RequestRefuse

The request that permissions that might be misused will not be granted.

Access property The Access property defines the network access method allowed by the security attribute. Only two values can be used:

Accept For allowing (or denying) binding to specific sockets

Connect

For allowing (or denying) connecting to specific remote sockets

Warning 

Be careful of the Accept Access property. The name makes it sound like you can limit incoming connections by remote address. This is not the case. Instead, it specifies a local socket address that will be restricted from binding.

The Host property The Host property defines the hostname or address in the security attribute. The value is specified as either a hostname string or an IP address octet string. Wildcards can also define more than one address on a network:

Host="192.168.1.*"

The Port property The Port property defines the TCP or UDP port in the security attribute. The value is specified as either an individual port number or the special value All, to represent all ports for the given transport and host.

The Transport property The Transport property defines the type of socket in the security attribute. The value is specified as one of the following string values:

All All transport types

Connectionless Connectionless transports, such as UDP

ConnectionOriented Connection-oriented transports, such as TCP

Tcp The TCP transport

Udp The UDP transport

Attributes are listed within the application code in the order in which they should be implemented. Each attribute is tested individually against the object attempting to access the application. As soon as one attribute denies access, the object is denied access to the application.

Using Declarative Security

Using declarative security in network applications is easy—just add the attribute statements within the class file and compile the program as normal. When the application is run, the socket permissions configured in the attribute lines will affect how the program is allowed to connect or bind to local sockets.

A Client Program

Listing 17.1 is the PickyTcpClient.cs program, which modifies the TcpClientSample.cs program from Listing 7.1 to incorporate declarative security restrictions that restrict what remote hosts the client can connect to.

Listing 17.1: The PickyTcpClient.cs program
Start example
using System;
using System.Net;
using System.Net.Sockets;
using System.Security;
using System.Security.Permissions;
using System.Text;
[SocketPermission(SecurityAction.Deny, Access="Connect", Host="127.0.0.1",
[SocketPermission(SecurityAction.Deny, Access="Connect", Host="192.168.0.2",
   Port="All", Transport="All")]
[SocketPermission(SecurityAction.Deny, Access="Connect", Host="192.168.1.100",
   Port="80", Transport="All")]
class PickyTcpClient
{
  public static void Main()
  {
   byte[] data = new byte[1024];
   string input, stringData;
   TcpClient server = null;
   Console.Write("Enter a host to connect to: ");
   string stringHost = Console.ReadLine();
   try
   {
     server = new TcpClient(stringHost, 9050);
   } catch (SocketException)
   {
     Console.WriteLine("Unable to connect to server");
     return;
   } catch (SecurityException)
   {
     Console.WriteLine(
      "Sorry, you are restricted from connecting to this server");
     return;
   }
   NetworkStream ns = server.GetStream();
   int recv = ns.Read(data, 0, data.Length);
   stringData = Encoding.ASCII.GetString(data, 0, recv);
   Console.WriteLine(stringData);
   while(true)
   {
     input = Console.ReadLine();
     if (input == "exit")
      break;
     ns.Write(Encoding.ASCII.GetBytes(input), 0, input.Length);
     ns.Flush();
     data = new byte[1024];
     recv = ns.Read(data, 0, data.Length);
     stringData = Encoding.ASCII.GetString(data, 0, recv);
     Console.WriteLine(stringData);
   }
   Console.WriteLine("Disconnecting from server...");
   ns.Close();
   server.Close();
  }
}
End example

As you can see, the network program code itself is the same as the original TcpClientSample.cs program—the difference is in the metadata defined at the start of the program. The security attributes specified at the beginning define which sockets are restricted from being accessed by the client. The following is a sample attribute:

[SocketPermission(SecurityAction.Deny, Access="Connect", Host="127.0.0.1",
   Port="All", Transport="All")]

This attribute restricts the client program from connecting to any port on host 127.0.0.1 (the local machine).

A SecurityException is thrown when a socket permission attribute is triggered. An additional catch statement captures the Exception and produces a customer-friendly error message to the user:

try
{
  server = new TcpClient(stringHost, 9050);
} catch (SocketException)
{
  Console.WriteLine("Unable to connect to server");
  return;
} catch (SecurityException)
{
  Console.WriteLine(
   "Sorry, you are restricted from connecting to this server");
  return;
}

The output from this program should look like:

C:\>PickyTcpCLient
Enter a host to connect to: 127.0.0.1
Sorry, you are restricted from connecting to this server
C:\>

As expected, the connection attempt was denied, and the SecurityException was thrown.

A Server Program

The declarative security feature also works for servers, but in a slightly different manner. The security attributes defined for the server program restrict access to the local socket. Address and port pairs defined in the security attribute relate to the local address and ports on the server.

If the address and port pair are configured to be restricted, the application program cannot perform a Bind() method on that socket. An example of a server security attribute would be the following:

[SocketPermission(SecurityAction.Deny, Access="Accept", Host="0.0.0.0",
   Port="9050", Transport="All")]

This security attribute prevents the application from binding to TCP port 9050 on the local machine.

Note 

Be careful when specifying the host part for Accept security attributes. If you use the machine’s internal loopback IP address, the application may still be able to bind to the external IP address. The special IP address IPAddress.Any (0.0.0.0) can represent all addresses for the interface.

Listing 17.2 shows the PickyTcpListener.cs program, which uses the original TcpListenerSample.cs program from Listing 7.2 and adds socket permission attributes.

Listing 17.2: The PickyTcpListener.cs program
Start example
using System;
using System.Net;
using System.Net.Sockets;
using System.Security;
using System.Security.Permissions;
using System.Text;
[SocketPermission(SecurityAction.Deny, Access="Accept", Host="0.0.0.0",
[SocketPermission(SecurityAction.Deny, Access="Accept", Host="0.0.0.0",
   Port="9051", Transport="All")]
[SocketPermission(SecurityAction.Deny, Access="Accept", Host="0.0.0.0",
   Port="9052", Transport="All")]
class PickyTcpListener
{
  public static void Main()
  {
   int recv;
   TcpListener newsock = null;
   byte[] data = new byte[1024];
   Console.Write("Enter port number to use: ");
   string stringPort = Console.ReadLine();
   int port = Convert.ToInt32(stringPort);
   try
   {
     newsock = new TcpListener(port);
     newsock.Start();
   } catch (SecurityException)
   {
     Console.WriteLine("Sorry, that port is unavailable");
     return;
   }
   Console.WriteLine("Waiting for a client...");
   TcpClient client = newsock.AcceptTcpClient();
   NetworkStream ns = client.GetStream();
   string welcome = "Welcome to my test server";
   data = Encoding.ASCII.GetBytes(welcome);
   ns.Write(data, 0, data.Length);
   while(true)
   {
     data = new byte[1024];
     recv = ns.Read(data, 0, data.Length);
     if (recv == 0)
      break;
   
     Console.WriteLine(
         Encoding.ASCII.GetString(data, 0, recv));
     ns.Write(data, 0, recv);
   }
   ns.Close();
   client.Close();
   newsock.Stop();
  }
}
End example

The PickyTcpListener.cs program restricts the application from accessing three separate ports (actually, six, if you count three for the TCP transport and three for the UDP transport). If the application attempts to access one of the restricted ports, a SecurityException is thrown, and an error message is produced.

 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows