Аутентификация, идентификация и несанкционированный доступ
Аутентификация - это процесс, в ходе которого на основании пароля, ключа или какой-либо иной информации, пользователь подтверждает, что
является именно тем, за кого себя выдает.
Первый способ неудобен тем, что в системе могут быть HTML-страницы, которым можно передать
параметры только методом GET, например, http://inforg.ru/main.html?login=1&pwd=fssdf.
И ваш логин и пароль будут закэшированы. Убрать все html-страницы в CGI-скрипты и работать
только методом POST неразумно, т.к. вы искусственно затормаживаете работу сервера. Как правило,
первый способ никогда не применяется. Наиболее распространены второй и третий способ.
Во втором и третьем способе логин и пароль передаются только один раза, а cookie и ключ генерируются
на определенное время. Cookie, как вы помните, это параметры с определенным сроком жизни,
которые хранятся на стороне клиента. Ключ - это тоже самое, только на стороне сервера.
Cookie имеют два принципиальных недостатка. Во-первых, они могут быть либо отключены, либо
просто не поддерживаться броузером. Кстати, была информация, что в Европе какой-то суд вообще
постановил, что данная технология незаконна, т.к. производит запись на компьютер пользователя
без его согласия. Во-вторых, пользователь может работать на чужом компьютере или в интернет-салоне
и тем самым есть риск, что после него кто-нибудь войдет в систему с этого компьютера. Cookie
можно устанавливать только на персональный компьютер пользователя, при условии, что он точно уверен,
что к компьютеру не имеют доступа злоумышленники.
Третий вариант, самый правильный и распространенный. После ввода логина и пароля вы генерируете
на сервере ключ с определенным сроком действия. И далее от скрипта к скрипту или HTML-документу
у вас таскается строка типа url?key=H13282i3hsk839bkjbBYasd. Каждый скрипт, получая ключ,
по ключу получает логин и пароль пользователя на сервере.
Такая система аутентификации
используется в нашей тестовой системе - http://test.itsoft.ru/.
int GetLoginPwd(MYSQL* pDB, const char* key,
LString *login, LString *pwd);
int GetKey(MYSQL* pDB, LString *key,
const char *login, const char *pwd, int expires);
Функция GetLoginPwd возвращает логин и пароль по ключу. В случае, если ключу не найдено соответствие возвращается ноль, иначе 1. Функция GetKey генерирует ключ по логину и паролю. Эти функции работают с базой данных MySQL, в которой хранится необходимая информация. Вам необходимо будет завести следующую таблицу: CREATE TABLE auth ( login varchar(25) NOT NULL default '', pwd varchar(25) NOT NULL default '', it_key varchar(50) NOT NULL default '', it_date datetime default NULL, //время жизни в секундах expires int(10) unsigned NOT NULL default '0' ) При входе в систему вы заполняете следующую HTML-форму. Ниже приведены исходные коды HTML-формы и программы аутентификации, которая генерирует ключ по логину и паролю, а затем перебрасывает пользователя на указанный url.
<form method=post action="/cgi-bin/auth">
<input type="hidden" name="path" value="student/auth">
<input type="hidden" name="url" value="main.html">
<table>
<tr><td>
Логин: </td><td><input type=text name=login></td></tr>
<tr><td>
Пароль: </td><td><input type=password name=password></td></tr>
<tr><td align=center colspan=2><input type=submit value="Вход"></td></tr>
</table>
</form>
/*
* (c) Copyright 1995-2000, Igor Tarasov
* http://itsoft.ru
* FidoNet: 2:5020/370.2 620.20 1103.5
* email: igor@itsoft.ru itarasov@rtuis.miem.edu.ru
* Phone: (095)916-89-51 916-89-63
*/
#include <stdio.h>
#include <stdlib.h>
#include <mysql.h>
#include <itcgi.h>
int main()
{
MYSQL* pDB;
MYSQL_RES* res;
//параметры соединения с базой
LString* db = CreateString();
LString* user = CreateString();
LString* pwd = CreateString();
LString* url = CreateString();
LString* sql_query = CreateString();
LString *key = CreateString();
LString *login = CreateString();
LString *password = CreateString();
pDB = mysql_init(NULL);
if(!pDB)
{
printError("Ошибка!", mysql_error(pDB));
return -1;
}
//считываем CGI-параметры и формируем SQL-запрос
//таблица student содержит данные о студентах,
//в том числе их логины и пароли
GetParamByName("url", url);
GetParamByIndex(2, login);
GetParamByIndex(3, password);
LString_Format(sql_query, "SELECT * FROM student WHERE id=%s AND
pwd=password('%s')", *login, *password);
GetRCParam(0, 0, "db", db);
GetRCParam(0, 0, "user", user);
GetRCParam(0, 0, "pwd", pwd);
//соединяемся с базой
if( !mysql_real_connect(pDB, NULL, *user, *pwd, *db, 0, NULL, 0) )
{
printError("Ошибка!", "mysql_real_connect: %s\n", mysql_error(pDB));
goto LABEL_END;
}
//выполняем SQL-запрос
if( mysql_query(pDB, *sql_query) )
{
printError("Error!", "mysql_query: SQL=%s<br> %s\n",
*sql_query, mysql_error(pDB));
goto LABEL_END;
}
//если логин и пароль правильные генерируем ключ
res = mysql_store_result(pDB);
if( res && res->row_count )
{
mysql_free_result(res);
if(!GetKey(pDB, key, *login, *password, 3600))
{
printError("Error!", "mysql_query: %s\n", mysql_error(pDB));
goto LABEL_END;
}
}
else
{
printError("Error!", "Password incorrect...");
goto LABEL_END;
}
//перенаправляем пользователя на
//http://test.itsoft.ru/main.html?key=key
printf("Location: http://%s/%s?key=%s\n\n",
getenv("SERVER_NAME"), *url, *key);
LABEL_END:
mysql_close(pDB);
DeleteString(db);
DeleteString(user);
DeleteString(pwd);
DeleteString(sql_query);
DeleteString(url);
DeleteString(key);
DeleteString(login);
DeleteString(password);
return 0;
}
=====Makefile====
#/*
# * (c) Copyright 1995-2000, Igor Tarasov
# * http://itsoft.ru
# * FidoNet: 2:5020/370.2 620.20 1103.5
# * email: igor@itsoft.ru itarasov@rtuis.miem.edu.ru
# * Phone: (095)916-89-51 916-89-63
# */
all: auth
auth: auth.c itcgi.a
gcc auth.c -L/usr/local/lib/mysql -I/usr/local/include/mysql \
-L/usr/local/lib -I/usr/local/include \
-o auth -lmysqlclient /usr/lib/itcgi.a -Wall -O3
strip auth
Далее, каждый CGI-скрипт считывает переменную key, производит аутентификацию. Ниже приведен
пример программы демонстрирующей данную возможность.
#include <stdio.h>
#include <mysql.h>
#include "itcgi.h"
#include "lstring.h"
int main()
{
MYSQL* pDB;
LString* db = CreateString();
LString* user = CreateString();
LString* pwd = CreateString();
LString* key = CreateString();
LString* HTML = CreateString();
char str[4096];
pDB = mysql_init(NULL);
if(!pDB)
{
printError("Внимание! Ошибка!", mysql_error(pDB));
return -1;
}
printf("Content-type: text/html; charset=windows-1251\n\n");
GetRCParam(0, 0, "db", db);
GetRCParam(0, 0, "user", user);
GetRCParam(0, 0, "pwd", pwd);
if( !mysql_real_connect(pDB, NULL, *user, *pwd, *db, 0, NULL, 0) )
{
printf("mysql_real_connect: %s\n", mysql_error(pDB));
goto LABEL_END;
}
//получаем значение ключа
//по которому определяем логин и пароль пользователя
GetParamByName("key", key);
if( !GetLoginPwd(pDB, *key, user, pwd) )
{
printf("Внимание! Ошибка!", "Error password!");
goto LABEL_END;
}
LString_SetString(HTML, "<tr><td><a
href=\"/cgi-bin/st_testinfo?id=%%id%%&key=%%key%%\"
title=\"%%description%%\">%%name%%</a></td>
<td>%%questions%%</td></tr>");
sprintf(str, "select test.id, test.name, questions, description
FROM test, question WHERE test.id=question.test_id
GROUP BY test.id, test.name, questions HAVING questions<=COUNT(*)");
if( GetHTMLFromSQL(pDB, str, HTML, NULL) )
{
LString_Replace(HTML, "%%key%%", *key);
printf("%s",*HTML);
}
LABEL_END:
mysql_close(pDB);
DeleteString(db);
DeleteString(user);
DeleteString(pwd);
DeleteString(key);
DeleteString(HTML);
return 0;
}
Следующей важной задачей в многопользовательских информационных системах является задача разграничения доступа. Мало только убедится в том, что пользователь ввел верные логин и пароль, необходимо также удостоверится, а разрешено ли ему выполнять запрашиваемые операции. Злоумышленник, например, может зарегистрироваться в вашей системе и удалить или получить доступ к чужим данным, если вы не будете выполнять процесс идентификации пользователей. Поэтому обязательно проверяйте допустимость выполняемой операции тем или иным пользователем. |