1

I am trying to learn how to use sockets to send files between pcs on my local network.

I am using ubuntu on my 'server' and my original plan was to create a ufw rule that allows all LAN connections but ask for a password when accepting the socket connection. That way only devices that are really supposed to communicate with the server would be accepted.

I do realise that creating ufw rules for static IPs would be an option but unfortunately I am dealing with dynamic IPs.

I have a text file of allowed keys on my 'server' and a text file containing one authentication key on the 'client'.

The server script looks like this:

#!/usr/bin/env python3

import socket

with open('/path/to/allowedKeys') as f:
    allowedKeys = []
    for line in f:
        allowedKeys.append(line.rstrip('\n'))

HOST = '127.0.0.1' #standard loopback interface address (localhost)
PORT = 9999

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((HOST, PORT))
serversocket.listen()
(clientsocket, address) = serversocket.accept()
with clientsocket:
    print('Connected by', address)
    while True:
        data = clientsocket.recv(1024)
        data = data.decode(encoding="utf-8")
        print('Received', repr(data))
        if data in allowedKeys:
            clientsocket.sendall(b'Thank you for logging in.')
            clientsocket.shutdown(socket.SHUT_RDWR)
            break
        else:
            clientsocket.sendall(b'Error: Failed authentication')
            clientsocket.shutdown(socket.SHUT_RDWR)
            break
   

and the client script looks like this:

#!/usr/bin/env python3

import socket

with open('/path/to/authenticationKey', 'r') as f: #read authenticationKey from textfile
    authenticationKey = f.readline().rstrip('\n')

authenticationKey = bytes(authenticationKey, encoding="utf-8") #convert authenticationKey to bytes
#authenticationKey = bytes('wrongKey', encoding="utf-8") #wrong Key for testing

HOST = '127.0.0.1'  #server hostname or IP address
PORT = 9999         #port used by the server

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(authenticationKey)
data = s.recv(1024)
s.shutdown(socket.SHUT_RDWR)
s.close()

print('Received', repr(data))

When I execute the scripts it looks like everything works as expected. I get either

Received 'nhjp9NIin987BUHBlkuULK98zJKn98JH'

or

Received 'wrongKey'

and the server shuts down successfully.

I have looked at these two related questions:

socket accept only specific addresses?

Server socket - accept connections only from IP addresses in the whitelist

While I cannot filter by IP it seems as if one must first accept the connection in order to authenticate the client.

I only want devices that possess an allowed key to be able to communicate with the server. All other connections should be shut down.

Since I still have very limited knowledge I would like to know whether this is the way to go or whether this leaves me open to any vulnerabilities.

Sean
  • 119
  • 13

1 Answers1

1

While I cannot filter by IP it seems as if one must first accept the connection in order to authenticate the client. I only want devices that possess an allowed key ..

Since you want to authenticate a client based on actual data (the key or proof of possession of the key) then you must first have a connection able to transfer the data from the client. With TCP this means that you have to accept the connection.

... whether this leaves me open to any vulnerabilities.

This is the usual way to go but it leaves you open to denial of service attacks. Creating a new connection takes resources, so by opening lots of connections an attacker can exhaust server resources. If all resources are exhausted this way even valid users can no longer access the server. See for example the SYN flood attack.

Depending on the setup of the client additional protections can be added. But these are outside of the python application and mostly out of scope of this question. But to get some ideas see the section about countermeasures in the Wikipedia article.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • What if my python script isn't running and checking incoming connections. Would someone now be able to connect to my server from my local network? – Sean May 01 '21 at 17:14
  • 1
    @Sean: Your Python script with the listening socket is basically the open door of a house where someone could enter. No open door, no entering - at least not through this door. Of course, the house might have other doors (i.e. other services, like a web server, mail server etc). – Steffen Ullrich May 01 '21 at 17:19
  • Now I'm a little confused. Once I set a ufw rule that allows all connections from my local network wouldn't that open the door? Or does that simply allow inbound connections but there has to be a service that actively accepts said connection? Since my knowledge is very limited I don't want to enable any mischief on accident. – Sean May 01 '21 at 17:37
  • 1
    @Sean: A firewall like ufw is similar to a doorman who can allow or deny access to the door itself, but cannot open a closed door. – Steffen Ullrich May 01 '21 at 18:03