Биллинговая система Nodeny
01 Мая 2024, 18:01:20 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Прекращена поддержка версии Nodeny 49
 
   Начало   Помощь Поиск Войти Регистрация  
Страниц: [1]
  Печать  
Автор Тема: Протокол авторизации  (Прочитано 16791 раз)
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« : 11 Августа 2009, 17:35:41 »

Протокол авторизации L2-авторизатора.

Комментарий: L2 не имеет никакой связи с layer2 или подобной, просто изначально много лет назад авторизатор был сделан для сети с именем L2, оттуда и пошло название.

Авторизация осуществляется по протоколу UDP, порт 7723. Внимание! Существует серьезный нюанс, касаемый UDP-соединения. Обычно, как происходит обмен данными по UDP протоколу:

Хост_1 посылает UDP пакет на Хост_2 порт, допустим, 7723. При этом у пакета src-port устанавливается системой (обычно из верхних портов 1024...65535). В дальнейшем хост_2 посылает ответы именно на этот порт.

В NoDeny иначе. Сначало объясню почему иначе. В L2-авторизатор встроен механизм пингования между авторизаторами по команде сервера. Т.е. администратор может дать команду "авторизатор такого-то клиента пропингуй авторизатор такого-то клиента и предоставь статистику по потерям". Такой пинг интересен двумя моментами:

1) позволяет отловить проблемный линк. Допустим, мы находимся в центре сети и пингуем клиента А и клиента Б. Проблемный линк (плохо обжатая/поврежденная витая пара) находится между нами и ближайшим к нам клиентом. Следовательно, мы получим потери как при пинговании клиента А, так и клиента Б. Если же мы дадим команду авторизатору А пропинговать Б, то можем увидеть - есть ли проблемы на всем протяжении коммуникакций от А до Б.

2) пингование идет не по icmp протоколу, а по udp и, как вы могли дагадаться, на порт 7723. Почему так? Потому что icmp протокол часто запрещен фаерволом, а udp порт 7723 клиент вынужден открыть для работы авторизатора.

Пока фича не активирована (в nol2auth.pl) т.к. с появлением управляемого оборудования появились иные методы отлова проблемных линков. Тем не менее, изначальный протокол построен исходя из предположения, что авторизатор будет слушать 7723 порт, т.е принимать входящие соединения.

Еще раз. Когда хост_1 посылает куда-то пакет, он открывает сокет, на который принимает ответные пакеты. В авторизаторе мы изначально биндим 7723 порт, т.е принимаем пакеты, это уже иной сокет!

Пример:

Авторизатор посылает на сервер пакет, dst_port=7723, src_port=12345 (выбирается системой случайным образом). Сервер авторизации, получив пакет, отправляет отвен не на порт 12345, а на порт 7723, т.е создает новый сокет. Итого: все udp пакеты между сервером авторизации и авторизатором идут каждый на новом сокете.

Фактически после посылки каждого пакета, мы закрываем сокет т.к не ждем на него ответа.

Описание протокола авторизации.

Протокол авторизации основан на том, что сервер формирует случайную строку, шифрует ее своим методом, отсылает клиенту, клиент расшифровывает строку, шифрует ее своим методом, отсылает серверу, сервер расшифровывает. Если в конечном итоге сервер получит исходную строку - процесс авторизации успешен.

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

Авторизация осуществляется по:

1) ip+пароль
2) ip+логин+пароль

В любом случае участвует ip, что является недостатком. Сервер, получив пакет, всегда смотрит на ip и ассоциирует его с клиентом. Если переданные данные правильные, то данный ip считается авторизированным клиентом иначе отвергается.

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

2) Сервер формирует случайную строку. Берет пароль клиента и разбивает на 2 части. Первую часть использует как ключ для шифрования случайно строки по AES. Зашифрованная строка отсылается клиенту

3) Клиент, получив зашифрованную строку, расшифровывает ее, используя 1-ю часть своего пароля как ключ шифрования. Т.е получает исходуную случайную строку.

Используя 2-ю часть пароля как ключ - заново шифрует случайную строку и отсылает ее серверу.

4) Сервер, получив, зашифрованные данные, расшифровывает их и, если они идентичны исходной случайной строке, открывает доступ клиенту.

5) Сервер отсылает статистику авторизатору (баланс, трафик, состояние авторизации и т.д)

Теперь подробней. Рассматриваем авторизацию ip+пароль.

Сперва сервер авторизации разбивает пароль каждого клиента на 2 части:

pass2 = первый 3 символа пароля
pass1 = оставшиеся символы пароля

Например, у клиента пароль 'killemall'

pass2 = 'kil'
pass1 = 'lemall'

Затем каждый пароль делается длиной  16 символов т.к. это необходимое требования для алгоритма шифрования AES (Rijndael в прошлом), а именно:

к pass2 дописываются буквы 'Z' (большие), а к pass1 - '0' (ноль). Если посмотреть внуть nol2auth.pl, То это строки:

  $U{$ip}{passwd2}=substr(substr($pass,0,3).'Z' x 16,0,16);
  $U{$ip}{passwd1}=substr($pass.'0' x 19,3,16);

Естественно, учитываем что пароли иногда могут меняться, т.е периодически обновляем информацию.

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

Обычно так происходит, когда фаервол клиента блокирует входящие пакеты - клиент отсылает и отсылает запросы, а ничего не получает в ответ.

Если же пароль клиента существует, сервер формирует случайную строку длиной 16 байт. В nol2auth это код:

$str=substr(rand().rand().'errorinlastline',2,16);
$str=new Crypt::Rijndael $str,Crypt::Rijndael::MODE_CBC;
$str=$str->encrypt(substr(rand().rand().'qazxswedcvfrtgbn',2,16));
$str=~s/,/-/g;

Почему именно так? Дело втом, что rand - возвращает случайное число, а нам нужно использовать как можно более случайную строку - с полным алфавитом символов от 0 до 255. Поэтому после получения случайного числа, мы его шифруем другим случайным числом и в итоге получаем хорошо сформированную случайную строку. Строки `errorinlastline` и `qazxswedcvfrtgbn` - здесь просто заполнители на случай, если число окажется длинной менее 16 символов - как я уже говорил, для AES нужны именно 16 байтные (128 битные) данные.

Шифруем случаную строку паролем pass2:

$crypt=new Crypt::Rijndael $U{$ip}{passwd2},Crypt::Rijndael::MODE_CBC;
$crypt_str=$crypt->encrypt($str);

Клиенту отправляем такую строку:

  'id'.$crypt_str.$id_session;

Т.е сперва идут 2 символа `id`, затем зашифрованная случайная строка, затем идентификатор сессии авторизации $id_session (полученный в пункте 1).

Клиент, получив пакет с начальными символами `id` - сравнивает свой идентификатор сессии с последними символами пакета, если не совпадает - игнорирует пакет. Иначе извлекает $crypt_str, расшифровывает, зашифровывает паролем pass1 и отсылает серверу в виде:

зашифрованная строка + состояние авторизации + идентификатор сесии

зашифрованная строка - 16 байт всегда состояние авторизации - 1 байт:
    a - запрос на включение полного доступа
    b - запрос на блокирование доступа
    c - запрос на включение доступа к сетям 2 направления
    e - запрос на включение полного доступа с просьбой разрешить пингование

продолжение следует...
« Последнее редактирование: 11 Августа 2009, 17:39:34 от Efendy » Записан
versus
Администратор
Спец
*****

Карма: 21
Offline Offline

Сообщений: 845


44306843
Просмотр профиля WWW Email
« Ответ #1 : 12 Августа 2009, 14:04:24 »

Прикладываю рабочий пример перлового авторизатора. Возможно в нем не реализован полностью протокол но для разобратся что ж в клиенте подойдет.
Записан
wizzard0
Пользователь
**

Карма: 0
Offline Offline

Сообщений: 5


Просмотр профиля Email
« Ответ #2 : 15 Августа 2009, 00:43:37 »

Жду продолжения Улыбающийся
Записан
wizzard0
Пользователь
**

Карма: 0
Offline Offline

Сообщений: 5


Просмотр профиля Email
« Ответ #3 : 19 Августа 2009, 03:14:55 »

Так, описанное - работает, статистику показывает Улыбающийся

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

Кстати, после получения случайного числа, мы его шифруем другим случайным числом и в итоге получаем хорошо сформированную случайную строку - такая операция не увеличивает пардон, увеличивает энтропию ровно в 2 раза, т.к. функция шифрования AES - биективная. Но при эффективной длине одного из ключей (первых 3 символов пароля) в 24 бита это, в общем-то, не самое слабое место. А так как я не верю в большой процент людей, которые пытаются учить криптографию, среди пользователей - то это вообще не проблема Улыбающийся

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

UPD: еще думаю над тем чтобы сделатьь "отдать мак адрес" тоже через авторизатор...
И есть мысль отдавать его вместо\или вместе со своим айпи, это поможет в случае наличия в сети левых дхцп серверов. Можно ведь в виндах начиная с 2000 конфигурировать айпишники программно (может можно и в 98, но я не пробовал)
« Последнее редактирование: 19 Августа 2009, 04:24:46 от wizzard0 » Записан
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« Ответ #4 : 19 Августа 2009, 08:10:19 »

Кстати, после получения случайного числа, мы его шифруем другим случайным числом и в итоге получаем хорошо сформированную случайную строку - такая операция не увеличивает пардон, увеличивает энтропию ровно в 2 раза, т.к. функция шифрования AES - биективная.
Дело не в энтропии - она итак достаточно высокая, до 10^16, если мы говорим об энтропии случайного 16 разрядного (в 10й системе) числа. Цель иная - получить алфавит не из 10 симолов (0..9), а из 256. Это должно усложнить перебор т.к., если не шифровать, то задача превращатся не в "получить случайную строку", а "получить строку в которой все символы будут цифрами, скорее всего это и будет искомая случайная строка". Ставим себя на место злоумышленника - пытаемся переборами паролей расшифровывать строку. Если получили что-то похожее на число (имеется ввиду, строку с  сиволами '0'..'9') - все, почти достоверно мы подобрали пароль. А если алфавит в 256 символом, то мы даже примерно не представляем как выглядит случайная строка
Записан
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« Ответ #5 : 19 Августа 2009, 08:53:42 »

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

При приеме udp пакете, авторизатор, прежде всего, определяет от кого он пришел: от сервера или нет - от этого зависит интерпретация пакета. Если от сервера, то пакеты могут быть таких типов:

id - стадия авторизации, когда сервер присылает пакет со случайной строкой
ok - авторизация успешная
sv - тоже, но сообщение авторизатору, то, что он админ. При этом открываются дополнительные табы для админа. С этой возможностью была хохма. Один чел заметил интересные фичи в моем авторизаторе и сумел переписать его на флеш, пока я отвлекся. Каково же его было удивление, когда придя домой он увидел равенство один в один его и моего авторизатора)
go - указание авторизатору выполнить команду. Выполняется только одна команда: монитринг процесса. Фича юзалась давно чтобы вычислить кто в сети занимается arp-спуффингом. Можно юзать чтоб вычислить кто проксики запускает или у кого вирусы в памяти)
no - неверная авторизация
er - ошибка

Тип пакета определяется первыми двумя символами в его данных. Напоминаю как происходит сеанс авторизации:
1) клиент делает запрос посылая на сервер пакет с выдуманным идентификатором сессии авторизации. Допустим, это 12345. Перед id сессии обязательно вставляется двухсимвольный код протокола, на данный момент актуальный - 25. Если протокол устарел, сервер может вернуть код "устаревший протокол авторизации" и авторизатор выведет сообщение "обновите авторизатор"

Итого посылаем сроку: 2512345

2) север получает строку, смотрит в базу ip от которого пришел пакет. Допустим такой ip есть в базе. Получаем его данные. Выдумываем случайную строку, шифруем данными клиента и отсылаем клиенту:

idlalalalalala12345

здесь lalalalalala - зашифрованная случайная строка. Ее длина фиксированная - 16 байт.

3) клиент получив пакет, смотрит на идентификатор сессии (он идет начиная с 18го байта), сравнивает со своим. Если не идентичен - пакет игнорируем.

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

Если наша сессия - расшифровываем, получаем случайную строку, снова шифруем и отправляем на сервер. К строке могут приклеиваться данные о процессе, который монитрится, но об этом в след раз.

Если от сервера пришел пакет 'no', то проверяем номер сессии (она идет сразу за 'no': 'no12345'). Если наша сессия, выводим клиенту "неверный пароль либо ip адрес", если не наша - пакет игнорируем.

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

Приходится принимать такие пакеты, но тем не менее пытаться авторизоваться, правда с бОльшим периодом авторизации

4) сервер получает строку, расшифровывает, сравнивает, все ок - посылает клиенту пакет первыми двумя символами 'ok', за которым идут зашифрованные данные, кратные 16 байт.

После расшифровки, получаем актуальные данные клиента (трафик, баланс и т.д.) - данные разделены символом запятая. Первый блок данных (перед первой запятой) - идентификатор запроса. Если не равен - пакет игнорируем и пытаемся снова авторизоваться через 20 секунд, иначе обрабатываем пакет и пытаемся авторизоваться через 40 сек (в моем авторизаторе).

Какие данные пересылаются - это проще посмотреть в исходнике сервера авторизации.
Записан
boddy
Новичок
*

Карма: 0
Offline Offline

Сообщений: 4

162944325
Просмотр профиля
« Ответ #6 : 24 Января 2010, 02:09:05 »

Не сочтите за некропост.
Изучая nol2auth.pl пробую написать свой агент и свой авторизатор.
Осталась одна проблема - в оригинальном агенте нет процедуры отключения авторизации. Или я слепой.
А мне важно отключить клиента при нажатии кнопки, а не через две минуты.
Что пробовал (бестолку):
Код:
"UPDATE $c{Db_usr_table} SET auth = 'no' WHERE id = $U{$ip}{id}";
через несколько секунд опять "on"

Код:
INSERT INTO dblogin set mid=$U{$ip}{id},act=0,time=unix_timestamp()
ставил наугад разные значения act, не помогло

здесь $com = q - состояние авторизации (то, которое "a - запрос на включение полного доступа")
у меня используется q в качестве запроса на отключение.
Код:
    my $rows;
    if ($com eq 'q') {
# my $sql="DELETE FROM dblogin WHERE mid=$U{$ip}{id}";
# my $sql="UPDATE $c{Db_usr_table} SET auth = 'no' WHERE id = $U{$ip}{id}";
my $sql="INSERT INTO dblogin set mid=$U{$ip}{id},act=47,time=unix_timestamp()";

    if( $dbha )
    {  # есть соединение с базой авторизации
       $rows=$dbha->do($sql);
       &Debug("dblogin [$rows]");
    }
next;
    }
подключение по оригинальным запросам "a,b..." идет в дальше в скрипте, т.е. переавторизации не происходит

лог авторизации 'a':
Цитировать
noBauth:                # === Пакет от 10.10.10.5
noBauth:                # Разрешена авторизация [1]
noBauth:                # Запрос на авторизацию. ID запроса=254414181515. Зашифрованный ключ послан в ответ
noBauth:                # === Пакет от 10.10.10.5
noBauth:                # 2й шаг авторизации. Авторизация успешна. Режим авторизации: a
noBauth:                # Авторизация записана в базу авторизаций
лог авторизации 'q':
Цитировать
noBauth:                # === Пакет от 10.10.10.5
noBauth:                # Разрешена авторизация [1]
noBauth:                # Запрос на авторизацию. ID запроса=255404080505. Зашифрованный ключ послан в ответ
noBauth:                # === Пакет от 10.10.10.5
noBauth:                # 2й шаг авторизации. Авторизация успешна. Режим авторизации: q
noBauth:                # dblogin [1]
Подскажите метод немедленного сброса авторизации, а не по таймауту в две минуты.
Желательно такой, для какого нет необходимости ковырять noserver.pl
Записан
boddy
Новичок
*

Карма: 0
Offline Offline

Сообщений: 4

162944325
Просмотр профиля
« Ответ #7 : 24 Января 2010, 02:52:21 »

Я сильно извиняюсь, не слепой - а тупой.
Весь день сношался не с тем...
Неудивительно что авторизацию в noserver.pl не нашел, ядро у нас nodeny.pl

Почистите, пожалуйста, если нагадил в теме.
Записан
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« Ответ #8 : 24 Января 2010, 12:00:49 »

в ранних версиях не было  команды "отключиться", отключалось автоматически по таймауту, т.е. если выключаешь авторизатор, то он, ессно, перестает авторизоваться и через небольшое время доступ блокируется. Сейчас такая команда введена, по-моему 'd' (надо в исходники глянуть)
Записан
boddy
Новичок
*

Карма: 0
Offline Offline

Сообщений: 4

162944325
Просмотр профиля
« Ответ #9 : 24 Января 2010, 23:23:40 »

в nol2auth.pl (49.32) такого нету, решение из nodeny.pl:
Код:
UPDATE users_trf SET now_on=0 WHERE uid=$U{$ip}{id};
UPDATE $c{Db_usr_table} SET auth = 'no'  WHERE id = $U{$ip}{id};
Записан
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« Ответ #10 : 25 Января 2010, 01:09:40 »

да, посмотрел в nol2auth.pl - там пока нет такого кода. Тем не менее самим ядром код отключения обрабатывается, в частности в radius это используется.

Навскидку:

Код:
# запишем в базу, что клиент авторизовался
    my $act=$com eq 'a'? 10 : $com eq 'c'? 11 : 12; # код авторизации

->

Код:
# запишем в базу, что клиент авторизовался
    my $act=$com eq 'a'? 10 : $com eq 'c'? 11 : $com eq 'd'? 19 : 12; # код авторизации

но это надо проверить в бою, сейчас уже поздно))
Записан
Страниц: [1]
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.20 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!