воскресенье, 31 января 2010 г.

Vkontakte: безопасная передача данных от клиента к серверу в iFrame приложениях

Не так давно Vkontakte ввело возможность разработки iFrame приложений. В связи с этим у многих разработчиков встал вопрос как защитить данные, передаваемые между приложением и api.

Я бы хотел предложить свое решение:
Защиту данных можно разделить на следующие аспекты:

1. Подтверждение информации о пользователе.
Чтобы получить достоверные подписанные данные о пользователе, необходимо использовать первый запрос к API в настройках приложения.
method=getProfiles&uids={viewer_id}&format=json&v=2.0
Тем самым мы получаем несколько параметров, один из которых нужный нам - viewer_id, а также сигнатуру данных (auth_key), подписанных секретным ключом, который гарантирует нам верность данных.
Т.е. на следующих этапах мы можем использовать информацию о пользователе, не боясь что данные были подменены.

2. Передача данных от пользователя к приложению
Чтобы скрыть секретный ключ и при этом иметь возможность передать данные на сервер придется использовать промежуточное звено - наш ajax обработчик.
Клиентский JavaScript:
function secureSend(_data, _callback) {
  $.ajax({
   type: "POST",
   url: "ajax.php",
   data: (_data),
   dataType: "json",
   success: function(data) {
     if(data.error != undefined) {
        error(data.error);
        return false;
     } else {
      _callback(data.response);
     }
   }
 });
}
На сервере же расположить скрипт обрабатывающий только обращения к API, которые пересылают данные от пользователя к серверу. Разрешить можно все действия, т.к. пользователя мы проверили на предыдущем этапе и уже тут он волен сколько угодно раз пересылать свои голоса к приложению :)
ajax.php, серверный скрипт
$vk_allow_methods = array("secure.withdrawVotes", "secure.getBalance");
$q = $_POST;
$d = "";
if(in_array($q['method'], $vk_allow_methods)) {
  $d = vkSend($q['method']);
}

function vkSend($method) {
  $server = "http://api.vkontakte.ru/api.php?";
  $key = "000";
  $aid = 1;
  
  $qr = array();
  $qr[] = 'method='.$method;
  $qr[] = 'api_id='.$aid;
  $qr[] = 'v=2.0';
  $qr[] = 'format=JSON';
  $qr[] = 'timestamp='.time();
  $qr[] = 'random='.rand(1, 999999);
  $qr[] = 'test_mode=1';
  sort($qr);
  
  $url4sign = implode("", $qr).$key;
  $sign     = md5($url4sign);
  $url      = implode("&", $qr)."&sig=".$sign;
  
  return file_get_contents($server.$url);
}

echo $d;

3. Передача данных от приложения к пользователю.
Такие события не должны ни в коем случае инициироваться клиентским кодом. Если необходимо перевести голоса со счета приложения на счет пользователя, то лучше воспользоваться запароленым скриптом, вызывающимся по cron или вручную администратором.

суббота, 9 января 2010 г.

Flex, PHP: Безопасная передача данных с клиента на сервер

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

1. Подписывание данных секретным ключом.
Это дает гарантию, что данные не будут подменены на промежуточных узлах до сервера.
Технология следующая:

a. Генерируем секретный ключ, о котором знает только приложения клиента и сервера
b. К передаваемым данным на сервер добавляем еще один параметр равный хэшу данных с секретным ключом. Пример на Flex:
var key:String = "0000-0000-0000-0000-0000";
var sreq:String = "method=setBalance&addMoney=1000"; //сам запрос
//отсортируем параметры
//чтобы последовательность параметром и на клиенте и на сервере была одинакова. Это гарантирует схождение хэшей.
sreq = sreq.split("&").sort().join("&");
//добавим к параметрам время, чтобы нельзя было продублировать запрос 
var now:Date = new Date();
var sec = now.getTime().toString().substr(0, -3);
//конечный запрос к серверу с дополнительным параметром = хэшу запроса и секретного ключа
sreq = sreq + "&timestamp="+sec+"&sig="+MD5.hash(sreq+key);
c. Сервер принимает запрос и проверяет данные используя свой секретный ключ.
К сожалению нельзя использовать четкое совпадение времени клиента и сервера, т.к. оно может отличаться или сообщение может идти до нескольких секунд. Из-за этого на сервере допускается расхождение timestamp до 100 секунд. Серверный код на PHP:
$_TIME    = $_SERVER['REQUEST_TIME'];//время запроса
$_KEY     = "0000-0000-0000-0000-0000";//тотже ключ, что и на клиенте
$_TIMEOUT = 100; //допустимое отклонение времени
// Проверим валидность данных
//присланная подпись должна сойтись со сгенерированной на основе закрытого ключа 
$q = $_GET;
//отсортируем также как в flex
unset($q['timestamp'], $q['sig']);
ksort($q);
$req = "";
foreach($q as $k=>$v) {
  $req .= $k."=".$v."&";
}
$req = substr($req, 0, -1);

if($_GET['sig'] != md5($req.$_KEY)) {
  //подписи не сошлись. Данные были подменены.
  exit;
}
//Проверим расхождение времени
if($_GET['timestamp'] + $_TIMEOUT < $_TIME) {
  //Расхождение более чем на 100 секунд. Прерываем запрос
  exit;
}

К сожалению такой метод не гарантирует нам, что запрос не будет перехвачен на промежуточном узле и не продублирован N раз в течении этих 100 секунд. Для устранения этого служит следующий пункт:

2. Проверка запроса на дублирование.
Идею я позаимствовал из TCP/IP. Добавим к запросу еще один параметр = счетчику сообщений, а на сервере будем хранить значение последнего счетчика. На клиенте достаточно сгенерировать счетчик = текущее значение + 1, а на сервере принять, проверить что новое значение больше старого и обновить серверный счетчик. Это гарантирует нам, что если злоумышленник перехватит запрос и пошлет его заново, то сервер его отвергнет, т.к. значение будет меньше хранящегося на сервере.
Для реализации этого механизма на сервере нам уже понадобится БД, а на клиенте дополнительный запрос на получение счетчика.

Под катом можно увидеть полный код клиента и сервера:

вторник, 5 января 2010 г.

Flex: Построение древовидного объекта по XML данным

Начал изучать Flex. Хочу поделиться некоторыми наработками, которые могут пригодиться.

Класс для создания древовидного объекта по XML строке.
Допустим у нас есть XML данные, полученные с удаленного хоста или еще как-нибудь. Xml может иметь смешанный тип, т.е. есть и обязательные теги (типа response), так и повторяющиеся на разных уровнях (section, id и т.д.)
Xml:

В программе удобней работать с объектом, чем с текстовыми данными, для этого служит следующий класс:
package Lib { 
  public class XMLTree {
  private var _xml:XML = null;
  private var _data:Object = new Object();
  private var _maxElem:int = 500;//ограничение на число элементов
     
  //конструктор, передается текстовый xml
  public function XMLTree(_xml:String) {
   this._xml = new XML(_xml); //создание объекта
   this.xmlParser(this._xml, this._data);//парсинг
  }
  
  public function getData():Object {
   return this._data;
  }
  
  //рекурсивный обход дерева
  private function xmlParser(node, obj:Object):void {
   var sObjName = "";
   //по каждому ответвлению
   for (var i = 0; i < node.length() && i < this._maxElem; i++) {
     sObjName = node[i].name();
     //если это ветка (имеет дочерей)
     if(node[i].hasComplexContent()) {
       //т.к. названия веток могут повторяться. Если свойство уже существует, то создается свойство с именем = имя + _ + уникальный идентификатор
       if(obj[sObjName] != undefined) {
         sObjName = sObjName + "_" + i;
       }
       //передаем ветку и текущее положение в деревянном объекте на следующий цикл рекурсии
       obj[sObjName] = new Object;
       this.xmlParser(node[i].children(), obj[sObjName]);
     } else {
       //создаем свойство с именем ветки XML объекта и текстовым значением
       obj[sObjName] = node[i].text();
     } //if
    }//for
   }//func
 }//class
}//package
Следующий код создаем объект и перечисляет значения первой ветки section дерева:
var xmlObj:XMLTree = new XMLTree(sXml);
var data:Object = xmlObj.getData();
for(var o in data.response.section) {
  Alert.show(data.response.section[o]);
}

четверг, 17 декабря 2009 г.

Рекурсивные (Иерархические) запросы

Дерево в БД можно представить достаточно просто:
ID | PID | NAME| VALUE
Куда сложней из такой таблицы вытаскивать данные. Можно это делать рекурсивно выполняя маленькие запросы, узнающие значение и родителя.
Оказывается эту задачу можно решить одним запросом используя лишь один T-SQL.
Рассмотрим на примере: необходимо выбрать все ветки/листья элемента, вывести значения элементов и построить полный путь до каждого.
Для этого можно использовать следующий запрос:
WITH tree ( data , id , pid , level , pathstr ) 
AS ( SELECT t.NAME, t.ID, t.PID, 0, CAST ( t.VALUE AS VARCHAR ( 4000 ) ) 
FROM table t
WHERE t.ID = 1 
UNION ALL 
SELECT t.NAME, t.ID, t.PID, t.level + 1 , CAST ( tr.pathstr + '\' + t.VALUE) AS VARCHAR ( 4000 ) ) 
FROM table t
INNER JOIN tree tr 
ON ( t.PID = tr.id ) 
) 
SELECT tr.* 
FROM tree tr 
ORDER BY tr.level, tr.pathstr 
Что делает каждая его часть:
WITH tree ( <список столбцов для выборки из дерева > ) 
AS ( 
<Начальное условие, откуда начнется рекурсия> 
Изначально путь = NAME корня, а уровень задан в 0
Строку с путем кастим к максимальному VARCHAR, т.к. путь может быть очень длинным.
UNION ALL 
<связка текущего запроса с деревом (родитель с идентификатором)>
Тут же мы увеличиваем уровень вложенности, и формируем следующий элемент пути
) 
<Тут мы работаем с полученными значениями, как с обычной таблицей>
Результат будет примерно такой:
id | pid | level | data                | pathstr
1  |  0  |   0   | Значение Корня      | Корень 
2  |  1  |   1   | Значение уровня 1   | Корень / Уровень 1
3  |  1  |   1   | Значение уровня 1.1 | Корень / Уровень 1.1
4  |  2  |   2   | Значение уровня 2   | Корень / Уровень 1 / Уровень 2

пятница, 11 декабря 2009 г.

Вывод результата выборки в строчку: FOR XML PATH

Бывает необходимость вывести результат выборки в строчку.
Рассмотрим на примере. Есть задача и список исполнителей, необходимо построчно вывести задачи и ответственных. В случае группировки по задаче, ответственному мы получим число записей = число задач * число ответственных, нам же требуется вывести задачи построчно. Это отлично реализуется с помощью инструкции MS SQL - FOR XML PATH, изначально используемой для формирования xml строки из выборки.

Пример кода: task - Задачи, executer - Исполнитель:
SELECT
e.name, -- название задачи
(SELECT t.name + ', ' -- список исполнителей для задачи через запятую
 FROM task t
 WHERE t.executor = e.id
 FOR XML PATH(''))
FROM executer e

Рассмотрим более интересный пример, более близкий к изначальному применению FOR XML PATH - сформируем CSV файл из таблицы одним запросом без всяких циклов:
SELECT
t.field1 + ';' + --объединяем список столбцов через разделитель
t.field2 + ';' +
t.field3 + ';' +
t.field4 + ';
' --перенос строки
FROM table t WHERE 1=1 FOR XML PATH('')
Если field не строка, то его нужно привести: CAST(field AS VARCHAR(50)).

Добавление для ORACLE
SELECT t.executor, wmsys.wm_concat(t.name) 
FROM FROM task t 
GROUP BY t.executor

воскресенье, 29 ноября 2009 г.

Векторный графический редактор в браузере на Raphael

SVG во всю набирает обороты и уже скоро сместит с пьедестала Flash. Не буду рассказывать о преимуществах, о этом можно прочитать в википедии.
На текущий момент у SVG есть один недостаток - нет поддержки в IE. У Microsoft собственный стандарт для векторной графики в браузере - VML.
Для решения этой проблемы разработана специальная библиотека Raphael, предоставляющая общий API для построения векторной графики, не зависимо от браузера.

В свою очередь я хочу представить графический редактор для построения векторной графики на основе RaphaelJS и чистоного SVG/VML.

Пример работы:
Opera (Firefox, Chrome, Safari - аналогично)
Internet Explorer
svg, raphael, canvas
Трансформация, поворот, масштабирование, закругление:
svg, raphael, canvas, Трансформация, поворот, масштабирование, закругление
svg, raphael, canvas

Попробовать демо редактора

Для просмотра списка возможностей читайте далее.

среда, 25 ноября 2009 г.

Исправление ошибок в модуле связи Punbb и Drupal

Исправил следующие ошибки в модуле:
1. Создание пользователя форума с пустым паролем.
2. Ошибка авторизации при привязке cookie к домену (проявлялось на некоторых браузерах).
3. Установка языка форума для пользователя, основываясь на глобальных настройках.
Спасибо golden[a]speechpro.com (Golden) за тестирование.

Ссылка для скачивания прежняя.

воскресенье, 22 ноября 2009 г.

NOT IN в MS SQL

В продолжение топика по оптимизации подзапросов в MS SQL, хотел бы сказать еще по поводу использования NOT IN. Точней его не использовании, т.к. в противном случае не подтягивается индекс и происходит полный перебор. Если есть возможность замените на эквивалентный запрос или перечисление констант.
Было:
...
field NOT IN (value1, value 2)
...
Стало:
...
field <> value1 AND field2 <> value2
...

суббота, 7 ноября 2009 г.

Модуль связи PunBB 1.3 и Drupal 6

Модуль связи PunBB и Drupal
Изменения:
1. Переработка модуля для версии Drupal 6
2. Усложнение авторизации и регистрации форума punbb привело к изменению модуля.

Напомню еще раз характеристики:
Только через Drupal. Рекомендую на пунбб вообще отключить регистрацию.
1. Единая регистрация
2. Единая авторизация
3. Единый выход
4. Единая смена учетных данных (В данной версии: почта, временная зона и пароль)
5. Анонс нодов на форуме

Доступ внутри node к информации о топике:
$node['punbb'] == array('id', //ид топика
                        'subject', //тема топика
                        'posted', //автор топика
                        'url'); //url до топика на форуме

Дата разработки: ноябрь 2009
Основное место обсуждения

Скачать архив (Размер файла: 8КБ)

воскресенье, 1 ноября 2009 г.

Синтез виртуальной среды с применением аналитических и скалярных функций возмущения

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

Оглавление:
Оглавление 6
Введение 9
1. Постановка задачи 11
1.1. Основные понятия и определения 11
1.2. Общее описание программной системы 11
2. Анализ методов и средств решения поставленной задачи 15
2.1. Теоретически основы 15
2.1.1. Физика процесса распространения света 15
2.1.2. Основная модель трассировки лучей 22
2.1.3. Способы задания свободных форм объектов 25
2.1.4. Функция возмущения в неявном виде 26
2.1.5. Функция возмущения в скалярном виде 28
2.1.6. Моделирование текстуры 28
2.1.7. Рельефное текстурирование 29
2.2. Аналитический обзор существующих систем синтеза воксельной графики 30
3. Анализ требований к программной системе 33
3.1. Анализ предметной области 33
3.2. Определение функциональности программной системы 34
3.3. Система приоритетов при разработке программной системы 34
4. Проектирование программной системы 36
4.1. Архитектура программной системы 36
4.2. Выбор инструментальных средств разработки 37
4.2.1. Выбор языка программирования 37
4.2.2. Выбор среды реализации 37
4.2.3. Выбор компилятора 38
4.2.4. Выбор прочих средств разработки 38
4.3. Проектирование структур данных, иерархии классов и алгоритмов 38
4.3.1. Описание структур данных 39
4.3.2. Описание алгоритмов программы 44
4.3.3. Оценка скорости работы алгоритма трассировки лучей 47
4.4. Проектирование пользовательского интерфейса 49
5. Реализация программной системы 50
5.1. Особенности реализации системы 50
5.1.1. Оценка объема исходного кода 54
5.2. Внешний вид сцен 54
6. Тестирование программной системы 59
6.1. Обоснование методики тестирования 59
6.2. Результаты тестирования 59
7. Внедрение системы 65
7.1. Руководство пользователя 65
7.2. Руководство программиста 66
8. Организационно-экономическая часть 68
8.1. Анализ и оценка стоимости объекта интеллектуальной собственности 68
8.1.1. Анализ объекта интеллектуальной собственности 68
8.1.2. Подходы к оценке стоимости объекта интеллектуальной собственности 70
8.1.3. Оценка стоимости объекта интеллектуальной собственности 75
8.2. Расчет показателей экономической эффективности 76
8.3. Выбор и обоснование методики ценообразования разработки 81
8.4. Способы коммерциализации объекта интеллектуальной собственности 83
9. Безопасность и экологичность проекта. 85
9.1. Анализ опасных и вредных факторов пользователей ПЭВМ 86
9.1.1. Опасные и вредные факторы при работе за мониторами. 88
9.2. Решения по охране труда 92
9.2.1. Проектирование естественного освещения 93
9.2.2. Проектирование искусственного освещения 96
9.3. Решения по обеспечению устойчивости функционирования в чрезвычайных ситуациях 99
9.3.1. Основные понятия чрезвычайных ситуаций 99
9.3.2. Информационная безопасность 101
Заключение 108
Список литературы 110
Приложение А 113
Листинг основных алгоритмов 113
Приложение Б 122
Организационно-экономическая часть 122
Приложение В 123
Безопасность и экологичность проекта 123
Приложение Г 124
Архитектура системы 124
Приложение Д 125
Общий алгоритм функционирования системы 125
Приложение Е 126
Тестирование системы 126
Приложение Ж 127
Алгоритм трассировки лучей 127
Далее примеры сцен и ссылка на скачку полного файла.