Автор работы: Пользователь скрыл имя, 22 Января 2013 в 20:48, дипломная работа
Исходя из этого, целью работы является разработать техногологию межсайтовой авторизации в сети интернет для портала ИМКН.
Для реализации технологии единого входа поставим перед собой следующие задачи:
Проанализировать существующие технологии единого входа (межсайтовой авторизации)
Настройка межсайтовой авторизации портала ИМКН
Тестирование настроек сайта или вопрос безопасности.
Введение 3
1.Технологии 5
1.1 1С - Битрикс 5
1.2 Технология переноса посетителей между сайтами 7
1.3 Модуль AD/LDAP 10
1.4 Схема работы модуля 13
1.5 Настройка многосайтовой конфигурации в 1С-битрикс. 14
1.6 OpenID 21
1.7 Кто контролирует OpenID? 22
1.8 Терминология OpenID 23
1.9 Simple Registration Extension 24
1.10 Применение технологии OpenID 26
1.11 Протокол Диффи-Хеллмана 27
1.12 Описание алгоритма 27
1.13 Недостатки OpenID в системе университета 35
1.14 Windows Live ID 37
1.15 SAML 38
2.Настройка межсайтовой авторизации между битриксом и удалёнными сайтами. 40
3.Безопасность при межсайтовом взаимодействии 49
Список литературы 51
Simple Registration Extension
Первоначально OpenID создавался
исключительно для аутентификации пользователя,
но после непродолжительной эксплуатации
появилась острая потребность в предоставлении
дополнительной информации о конечном
пользователе. Для решения этой проблемы
было разработано расширение протокола
— Simple Registation
Extension. Провайдеры аутентификации,
которые поддерживают это расширение,
могут хранить информацию о т. н. «персонах».
«Персона» — запись, содержащая Ваше имя,
адрес электронной почты и другие данные,
которые обычно требуются для регистрации
на сайтах. Любая персона может быть выбрана,
как «публичная» — её содержимое сможет
посмотреть каждый даже без согласия персоны
на это.
(Рис. № 1) Схема работы OpenID
На рис. №1 изображён порядок работы OpenID-аутентификации. Слева - OpenID-провайдеры ,а справа - другие сайты, поддерживающие OpenID-регистрацию. Мы будем считать, что в центре - это профиль пользователя. Справа - сайты, на которые он хочет залогиниться, указав в качестве OpenID-аккаунта ссылку на свой профиль. А слева - его, пользователя, OpenID-провайдеры, которых, к слову, он может и не иметь вовсе, иметь всего один (на схеме изображен черным цветом), или иметь несколько (на схеме дополнительные связи к другим OpenID-провайдерам указаны серым цветом).
В OpenID используется протокол, которые позволяют двум сторонам сгенерировать общий ключ К, не передавая его по каналу который называется — Diffie-Hellman Key Exchange Protocol (протокол Диффи-Хелмана) .
Обмен ключа Диффи-Хеллмэн является шифровальным протоколом, который разрешает две стороны, у которых нет никакого предшествующего знания друг друга, чтобы совместно установить общий секретный ключ по опасному каналу коммуникаций. Этот ключ может тогда использоваться, чтобы зашифровать последующие коммуникации, используя симметрический ключевой шифр.
Предположим, что обоим абонентам известны некоторые два числа g и p (например, они могут быть «зашиты» в программное обеспечение), которые не являются секретными и могут быть известны также другим заинтересованным лицам. Для того, чтобы создать неизвестный более никому секретный ключ, оба абонента генерируют большие случайные числа: первый абонент — число a, второй абонент — число b. Затем первый абонент вычисляет значение A = gamod p и пересылает его второму, а второй вычисляет B = gbmod p и передаёт первому. Предполагается, что злоумышленник может получить оба этих значения, но не модифицировать их (то есть у него нет возможности вмешаться в процесс передачи). На втором этапе первый абонент на основе имеющегося у него a и полученного по сети B вычисляет значение Bamod p = gabmod p, а второй абонент на основе имеющегося у него b и полученного по сети A вычисляет значение Abmod p = gabmod p. Как нетрудно видеть, у обоих абонентов получилось одно и то же число: K = gabmod p. Его они и могут использовать в качестве секретного ключа, поскольку здесь злоумышленник встретится с практически неразрешимой (за разумное время) проблемой вычисления gabmod p по перехваченным gamod p и gbmod p, если числа p,a,b выбраны достаточно большими.
Параметрами протокола являются p – большое простое число, g – порождающий элемент мультипликативной группы Zp*.
1. A→B: ga mod p (где x – случайное секретное число);
2. B→A: gb mod p (где y – случайное секретное число);
3. A: вычисляет K=Ba mod p;
4. B: вычисляет K=Ab mod p.
В результате A и B получают общий сеансовый ключ K.
Итак, как всё это выглядит на практике.
У нас есть 2 файла : index.php и class.openid.php.
При заходе на сайт клиента OpenID пользователь попадает на index.php ,где вводит свой OpenID Login
И после этого редиректится на сайт провайдера на котором пользователю предоставляется возможность авторизироваться. Еcли авторизация прошла успешно происходит генерация трёх переменных g,a,p и вычисляется A= ga mod p кторорый отправляется клиенту переменные g,p,A через GET запрос. С помощью функции ValidateWithServer() в class.openid.php переданные переменные кодируются в безопасное представление и вычисляется B = gb mod p и отправляет серверу. В результате если общий сеансовый ключ совпадает то происходит авторизация на стороне клиента OpenID.
Структура файла Index.php
<?
require('class.openid.php');
if ($_POST['openid_action'] == "login"){
$openid = new SimpleOpenID;
$openid->SetIdentity($_POST['
$openid->SetTrustRoot('http://
$openid->SetRequiredFields(
$openid->SetOptionalFields(
if ($openid->GetOpenIDServer()){
$openid->SetApprovedURL('http:
$openid->Redirect();
}else{
$error = $openid->GetError();
echo "ERROR CODE: " . $error['code'] . "<br>";
echo "ERROR DESCRIPTION: " . $error['description'] . "<br>";
}
exit;
}
else if($_GET['openid_mode'] == 'id_res'){
$openid = new SimpleOpenID;
$openid->SetIdentity($_GET['
$openid_validation_result = $openid->ValidateWithServer();
if ($openid_validation_result == true){
echo "VALID";
}else if($openid->IsError() == true){
$error = $openid->GetError();
echo "ERROR CODE: " . $error['code'] . "<br>";
echo "ERROR DESCRIPTION: " . $error['description'] . "<br>";
}else{
echo "INVALID AUTHORIZATION";
}
}else if ($_GET['openid_mode'] == 'cancel'){ // User Canceled your Request
echo "USER CANCELED REQUEST";
}
?>
<html>
<head>
</head>
<body>
<div>
<fieldset id="openid">
<legend>OpenID Login</legend>
<form action="<?echo
'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PATH_INFO"];
?>" method="post" onSubmit="this.login.disabled=
<input type="hidden" name="openid_action" value="login">
<div><input type="text" name="openid_url" class="openid_login"><input type="submit" name="login" value="login >>"></div>
</form>
</fieldset>
</div>
</body>
</html>
Структура файла class.openid.php
<?
class SimpleOpenID{
var $openid_url_identity;
var $URLs = array();
var $error = array();
var $fields = array();
function SimpleOpenID(){
if (!function_exists('curl_exec')
die('Error: Class SimpleOpenID requires curl extension to work');
}
}
function SetOpenIDServer($a) { $this->URLs['openid_server'] = $a;}
function SetTrustRoot($a) { $this->URLs['trust_root'] = $a;}
function SetCancelURL($a) { $this->URLs['cancel'] = $a;}
function SetApprovedURL($a) { $this->URLs['approved'] = $a;}
function SetRequiredFields($a){
if (is_array($a)){
$this->fields['required'] = $a;
}else{
$this->fields['required'][] = $a;
}
}
function SetOptionalFields($a){
if (is_array($a)){
$this->fields['optional'] = $a;
}else{
$this->fields['optional'][] = $a;
}
}
function SetIdentity($a){
if(strpos($a, 'http://') === false) {
$a = 'http://'.$a;
}
/*
$u = parse_url(trim($a));
if (!isset($u['path'])){
$u['path'] = '/';
}else if(substr($u['path'],-1,1) == '/'){
$u['path'] = substr($u['path'], 0, strlen($u['path'])-1);
}
if (isset($u['query'])){ // If there is a query string, then use identity as is
$identity = $a;
}else{
$identity = $u['scheme'] . '://' . $u['host'] . $u['path'];
}*/
$this->openid_url_identity = $a;
}
function GetIdentity(){
return $this->openid_url_identity;
}
function GetError(){
$e = $this->error;
return array('code'=>$e[0],'
}
function ErrorStore($code, $desc = null){
$errs['OPENID_NOSERVERSFOUND'] = 'Cannot find OpenID Server TAG on Identity page.';
if ($desc == null){
$desc = $errs[$code];
}
$this->error = array($code,$desc);
}
function IsError(){
if (count($this->error) > 0){
return true;
}else{
return false;
}
}
function splitResponse($response) {
$r = array();
$response = explode("\n", $response);
foreach($response as $line) {
$line = trim($line);
if ($line != "") {
list($key, $value) = explode(":", $line, 2);
$r[trim($key)] = trim($value);
}
}
return $r;
}
function OpenID_Standarize($openid_
$u = parse_url(strtolower(trim($
if ($u['path'] == '/'){
$u['path'] = '';
}
if(substr($u['path'],-1,1) == '/'){
$u['path'] = substr($u['path'], 0, strlen($u['path'])-1);
}
if (isset($u['query'])){
return $u['host'] . $u['path'] . '?' . $u['query'];
}else{
return $u['host'] . $u['path'];
}
}
function array2url($arr){ if (!is_array($arr)){
return false;
}
foreach($arr as $key => $value){
$query .= $key . "=" . $value . "&";
}
return $query;
}
function FSOCK_Request($url, $method="GET", $params = ""){
$fp = fsockopen("ssl://www.myopenid.
if (!$fp) {
$this->ErrorStore('OPENID_
return false;
} else {
$request = $method . " /server HTTP/1.0\r\n";
$request .= "User-Agent:
Simple OpenID PHP Class (http://www.phpclasses.org/
$request .= "Connection: close\r\n\r\n";
fwrite($fp, $request);
stream_set_timeout($fp, 4); // Connection response timeout is 4 seconds
$res = fread($fp, 2000);
$info = stream_get_meta_data($fp);
fclose($fp);
if ($info['timed_out']) {
$this->ErrorStore('OPENID_
} else {
return $res;
}
}
}
function CURL_Request($url, $method="GET", $params = "") { if (is_array($params)) $params = $this->array2url($params);
$curl = curl_init($url . ($method == "GET" && $params != "" ? "?" . $params : ""));
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_HTTPGET, ($method == "GET"));
curl_setopt($curl, CURLOPT_POST, ($method == "POST"));
if ($method == "POST") curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl);
if (curl_errno($curl) == 0){
$response;
}else{
$this->ErrorStore('OPENID_
}
return $response;
}
function HTML2OpenIDServer($content) {
$get = array();
// Get details of their OpenID server and (optional) delegate
preg_match_all('/<link[^>]*
preg_match_all('/<link[^>]*
$servers = array_merge($matches1[1], $matches2[1]);
preg_match_all('/<link[^>]*
preg_match_all('/<link[^>]*
$delegates = array_merge($matches1[1], $matches2[1]);
$ret = array($servers, $delegates);
return $ret;
}
function GetOpenIDServer(){
$response = $this->CURL_Request($this->
list($servers, $delegates)
= $this->HTML2OpenIDServer($
if (count($servers) == 0){
$this->ErrorStore('OPENID_
return false;
}
if ($delegates[0] != ""){
$this->openid_url_identity = $delegates[0];
}
$this->SetOpenIDServer($
return $servers[0];
}
function GetRedirectURL(){
$params = array();
$params['openid.return_to']
= urlencode($this->URLs['approve
$params['openid.mode'] = 'checkid_setup';
$params['openid.identity']
= urlencode($this->openid_url_
$params['openid.trust_root']
= urlencode($this->URLs['trust_
if (count($this->fields['
$params['openid.sreg.required'
}
if (count($this->fields['
$params['openid.sreg.optional'
}
return $this->URLs['openid_server'] . "?". $this->array2url($params);
}
function Redirect(){
$redirect_to = $this->GetRedirectURL();
if (headers_sent()){
echo '<script language="JavaScript"
type="text/javascript">window.
echo $redirect_to;
echo '\';</script>';
}else{ // Default Header Redirect
header('Location: ' . $redirect_to);
}
}
function ValidateWithServer(){
$params = array(
'openid.assoc_handle' =>
urlencode($_GET['openid_assoc_
'openid.signed' => urlencode($_GET['openid_
'openid.sig' => urlencode($_GET['openid_sig'])
);
// Send only required parameters to confirm validity
$arr_signed = explode(",",str_replace('sreg.
for ($i=0; $i<count($arr_signed); $i++){
$s = str_replace('sreg_','sreg.', $arr_signed[$i]);
$c = $_GET['openid_' . $arr_signed[$i]];
// if ($c != ""){
$params['openid.' . $s] = urlencode($c);
// }
}
$params['openid.mode'] = "check_authentication";
// print "<pre>";
// print_r($_GET);
// print_r($params);
// print "</pre>";
$openid_server = $this->GetOpenIDServer();
if ($openid_server == false){
return false;
}
$response = $this->CURL_Request($openid_
$data = $this->splitResponse($
if ($data['is_valid'] == "true") {
return true;
}else{
return false;
}
}
}
?>
После тестированая технологии на первый взгляд показалась не совсем удобной с одной стороны, если говорить о плюсах единый логин и пароль для любого сайта который поддерживает эту технологию это находка для пользователя которому надоело вечная авторизация, тем более что в новой версии протокола на сайт клиента передаётся не только индификационные данные но и личная информация ФИО, дата рождения и т.д. А с другой если глядеть с точки безопасности провайдер OpenID может представиться своим пользователем. Это возможно или в случае недобропорядочности провайдера, или в случае его взлома.
Пользователь должен доверять провайдеру, так как тот может узнать, какие сайты посещал владелец OpenID. Хотя, с другой стороны, провайдер обычно даёт пользователю OpenID возможность проконтролировать, на каких сайтах был использован его логин, чтобы заметить кражу пароля.
Система OpenID для университета не идеальна, ещё одним минусом является то, что нет чёткого контроля за пользователями так как в системе где поддерживается OpenID авторизация может авторизироватся любой выбрав себе провайдера и пошел гулять по всем сайтом с поддержкой этой технологии. Зарегистрировавшись на одном из OpenID провайдеров он получает доступ ко всем ресурсам которые доступны обычному пользователю на других сайтах, но студенты у нас не являются простыми пользователями для них нужно открывать тесты, лабораторные и т.д.
Сейчас система в университете работает так при поступление новых студентов они вбиваются в базу с присвоение группы которая им назначается, либо можно вбить их в экселевсикий файлик и импортировать в базу, и в процессе учёбы для той или иной группы открывается блоки с заданиями, где предварительно старосте выдаётся список в котором напротив каждой фамилии написан логин и пароль для доступа на сайт.
В openid ситуация выглядит следующим образом после того как все авторизировались на портале к примеру imkn.kib.ru предварительно выбрав себе провайдера, преподаватель должен переписать все логины (ivanov.opnid.com, petrov.myopenid.com, sidirov.ya.ru (это openid яндекса)) и в процессе искать этого человека в базе и закреплять за ним определенную группу в которой он учится, а если кого то из студентов не было в университете, а тест открыли на неделю а преподаватель уехал в командировку возникает проблема. Ещё один минус даже больше не удобство то что если студент выбрал себе провайдера который не поддерживает передачу доп. данных (ФИО,дата рождения и т.д.) ( это возможно у тех провайдеров у которых старая версия протокола) преподавателю придётся самому мало того чтоб подтверждать пользователя в базе назначать ему группу так ещё и заполнять ФИО, дату рождения так как в базе клиента от openid провайдера останется только логин (ivanov.openid.com).