Шаг 212.
Python: сборник рецептов.
Сети и веб-программирование. Простая аутентификация клиентов

    На этом шаге мы рассмотрим реализацию этой задачи.

Задача

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

Решение

    Простой, но при этом эффективный способ аутентификации может быть реализован путем хендшейка при соединении с использованием модуля hmac. Вот пример:

import hmac
import os

def client_authenticate(connection, secret_key):
    '''
    Аутентифицирует клиента на удаленном сервере.
    connection представляет сетевое соединение.
    secret_key - это ключ, известный только клиенту и серверу.
    '''
    message = connection.recv(32)
    hash = hmac.new(secret_key, message)
    digest = hash.digest()
    connection.send(digest)

def server_authenticate(connection, secret_key):
    '''
    Запрашивает аутетентификацию клиента.
    '''
    message = os.urandom(32)
    connection.send(message)
    hash = hmac.new(secret_key, message)
    digest = hash.digest()
    response = connection.recv(len(digest))
    return hmac.compare_digest(digest, response)

    Основная идея в том, что до установки соединения сервер предоставляет клиенту сообщение, состоящее из случайных байтов (в данном случае они генерируются os.random()). И клиент, и сервер вычисляют криптографический хеш этих случайных данных, используя hmac и секретный ключ, известный только обеим сторонам. Клиент посылает вычисленный дайджест обратно на сервер, где они сравниваются, после чего принимается решение - принимать соединение или нет.

    Сравнение получившихся дайджестов должно выполняться с помощью функции hmac.compare_digest(). Она написана таким образом, чтобы предотвратить атаки на основе анализа тайминга, и должна быть использована вместо стандартного оператора сравнения (==).

    Чтобы использовать эти функции, вы должны включить их в существующий сетевой код или код системы обмена сообщениями. Например, серверный код с сокетами может выглядеть как-то так:

from socket import socket, AF_INET, SOCK_STREAM
from auth import server_authenticate

secret_key = b'peekaboo'

def echo_handler(client_sock):
    if not server_authenticate(client_sock, secret_key):
        client_sock.close()
        return
    while True:
        msg = client_sock.recv(8192)
        if not msg:
            break
        client_sock.sendall(msg)

def echo_server(address):
    s = socket(AF_INET, SOCK_STREAM)
    s.bind(address)
    s.listen(5)
    while True:
        c,a = s.accept()
        echo_handler(c)

print('Echo server running on port 18000')

echo_server(('', 18000))

    В клиенте нужен примерно такой код:

from socket import socket, AF_INET, SOCK_STREAM
from auth import client_authenticate

secret_key = b'peekaboo'

s = socket(AF_INET, SOCK_STREAM)
s.connect(('localhost', 18000))
client_authenticate(s, secret_key)
s.send(b'Hello World')
resp = s.recv(1024)
print('Got:', resp)


Обсуждение

    Обычно аутентификация на базе hmac используется для внутренних систем обмена сообщениями и взаимодействия между процессами. Например, если вы пишете систему, в которой общаются между собой процессы, запущенные на кластере, вы можете использовать этот подход, чтобы быть уверенным, что соединяться между собой могут только процессы, у которых есть соответствующие права. Например, HMAC-аутентификация используется библиотекой multiprocessing, когда она устанавливает сообщение между подпроцессами.

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

    Алгоритм аутентификации, используемый hmac, базируется на криптографических функциях хеширования, таких как MD5 и SHA-1, и в деталях описан в IETF RFC 2104.

    На следующем шаге мы рассмотрим добавление SSL в сетевые сервисы.




Предыдущий шаг Содержание Следующий шаг