Я планирую включить сервер в разрабатываемое мной приложение (никакие передаваемые данные не будут конфиденциальными). Я настроил переадресацию портов на своем маршрутизаторе, которая указывает на сервер в сети. Вот фрагмент кода на стороне сервера:
import time
import threading
import socketserver
import ssl
class ThreadedTCPRequestHandler(socketserver.StreamRequestHandler):
def handle(self):
# Each new request is handled by this function.
data = str(self.request.recv(4096), 'utf-8')
print('Request received on {}'.format(time.ctime()))
print('{} wrote: {}'.format(self.client_address[0], data))
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'utf-8')
self.request.sendall(response)
class TLSTCPServer(socketserver.TCPServer):
def __init__(self, server_address, request_handler_class, certfile, keyfile, ssl_version=ssl.PROTOCOL_TLSv1_2,
bind_and_activate=True):
socketserver.TCPServer.__init__(self, server_address, request_handler_class, bind_and_activate)
self.certfile = certfile
self.keyfile = keyfile
self.ssl_version = ssl_version
def get_request(self):
newsocket, fromaddr = self.socket.accept()
connstream = ssl.wrap_socket(newsocket,
server_side=True,
certfile=self.certfile,
keyfile=self.keyfile,
ssl_version=self.ssl_version)
return connstream, fromaddr
class ThreadedTCPServer(socketserver.ThreadingMixIn, TLSTCPServer):
pass
if __name__ == "__main__":
HOST, PORT = "0.0.0.0", 6001
# Creates a server that handles each request on a separate thread. "cert.pem" is the TLS certificate and "key.pem"
# is the TLS private key (kept only on the server).
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler, "cert.pem", "key.pem")
ip, port = server.server_address
print('Started server\n')
server.serve_forever()
А вот и клиентский код:
import socket
import time
import ssl
HOST = 'localhost' # This should be the server's public IP when used in production code
PORT = 6001
data = 'Hello!'
start_time = time.time()
try:
# Connect to server and send data
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_sock = ssl.wrap_socket(sock,
ca_certs = "cert.pem",
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1_2)
ssl_sock.connect((HOST, PORT))
ssl_sock.sendall(data.encode())
# Receive data from the server and shut down
received = ssl_sock.recv(4096)
elapsed_tie = round(time.time() - start_time, 2)
print("Sent: {}".format(data))
print("Received: {}".format(received.decode('utf-8')))
print("Elapsed: {}s \n".format(elapsed_tie))
ssl_sock.close()
except Exception as e:
print(format(e))
Обратите внимание, что cert.pem и key.pem генерируются с помощью этой команды в терминале Mac или Linux: openssl req -newkey rsa:4096 -nodes -sha512 -x509 -days 3650 -nodes -out cert.pem -keyout key.pem
Сервер использует TLS для защиты данных, а запросы обрабатываются в отдельных потоках. Объем вычислений, выполняемых для каждого запроса, будет относительно небольшим, поскольку он будет в основном состоять из чтения и записи небольших объемов данных в базу данных с каждым запросом.
Меня больше всего беспокоит то, что кто-то злонамеренно может определить публичный IP-адрес сервера и выполнить DDOS-атаку. Один из способов смягчить это - отклонить слишком частые запросы с одного и того же клиентского адреса. Есть ли другие способы смягчить такие атаки? Кроме того, стоит ли запускать безопасный сервер на Python или мне стоит поискать в другом месте? Заранее спасибо.
--- РЕДАКТИРОВАТЬ ---
Я думал проверить, не делает ли один и тот же пользователь слишком много запросов за определенное время. Поскольку запросы выполняются по таймеру (скажем, 5 секунд), любые запросы, выполняемые чаще, считаются подозрительными. Пока входящие запросы не перегружают полосу пропускания маршрутизатора, теоретически я должен иметь возможность отклонять некоторые запросы. Однако, если несколько машин делают запросы из одной и той же сети, я не могу просто смотреть на общедоступные IP-адреса входящих запросов, так как я могу отклонять совершенно действительные запросы. Есть ли какой-либо идентификатор, позволяющий идентифицировать машину, отправляющую запрос?






Когда до вас доходит DDoS-атака, уже слишком поздно. Пакеты прибыли на ваш сервер и заполняют ваш канал. Что бы вы ни делали, они уже есть - многие из них. Вы можете отказаться от них, но другие люди все равно не смогут связаться с вами.
Защита от DDoS-атак должна осуществляться по восходящей линии связи кем-то, кто сможет решить, является ли пакет вредоносным или нет. Это волшебная операция, за которую такие компании, как Cloudflare или Akamai, заставляют вас много платить.
Другая возможность - изменить вашу запись DNS так, чтобы точка находилась где-то еще во время атаки. Это действительно здорово, чтобы ваши клиенты знали, что ваш сайт «находится на обслуживании, скоро вернется».
Первое, о чем вы упомянули, называется дросселирование. Это защищает (в вашем случае) учетную запись пользователя от перебора. Вторая часть (как однозначно идентифицировать устройства) - это на самом деле упомянутая мною «волшебная операция»: способность решать, является ли конкретный вызов / соединение законным или нет. Для этого нет простых решений, и сервисы по предотвращению DDoS-атак продают именно эти знания. На самом деле вы можете защитить учетную запись от грубой силы (путем регулирования IP-адресов и, возможно, блокировки учетной записи - это вопрос анализа рисков), но не более того.
Я думал проверить, не делает ли один и тот же пользователь слишком много запросов за определенное время. Поскольку запросы выполняются по таймеру (скажем, 5 секунд), любые запросы, выполняемые чаще, считаются подозрительными. Пока входящие запросы не перегружают полосу пропускания маршрутизатора, теоретически я должен иметь возможность отклонять некоторые запросы. Однако, если несколько машин делают запросы из одной и той же сети, я не могу просто смотреть на общедоступные IP-адреса входящих запросов, так как я могу отклонять совершенно действительные запросы. Есть ли какой-либо идентификатор, позволяющий идентифицировать машину, отправляющую запрос?