Записки о софтверном бизнесе

Автореспондеры – зло

September 29th, 2011 Posted in Uncategorized | No Comments »

Ничто меня не бесит так, как автореспондеры. После каждой рассылки насыпается пара сотен автоматических ответов. Я получил ваше письмо, я не получил, но получу и прочту, меня нет на месте, наш специалист свяжется с вами, я в отпуске, я родил малыша, я уволился. Да кому какое дело, что там у тебя. Не о тебе речь вообще.

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

 

 

 

 

Traveliving или живи путешествуя

September 26th, 2011 Posted in Uncategorized | 8 Comments »

Мотивационный пост. Коллекция блогов людей и семей, сделавших путешествие образом жизни. Как обычно, я им всем немного завидую.

1. Джерри и Адриана

Джерри - разработчик приложений для iPhone. Путешествует с женой Адрианой, работает откуда придется и у него это неплохо получается.

2. The Unstoppable family

Вы скажете стиль жизнь-путешествие не подходит для семейных пар с детьми и будете в чем-то правы. Но Unstoppable family путешествует с дочерью уже три года и все у них получается. Дочь ходит в школы, там где они живут в данный момент и так же занимаются домашним обучением.

Советую посмотреть вопросы и ответы. Самым полезным для путешествий иностранным языком они считают испанский.

Зарабатывают они на жизнь какой-то мутной ерундой типа MLM, но в остальном интересно почитать.

3. Аджей и Маша

Профессиональные трэвеливеры, в путешествии уже несколько лет. Сдают квартиру в Москве, немного подрабатывают фрилансерством и блогом. Путешествуют по Юго-Восточной Азии. Пишут интересно.

4. Другая жизнь

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

Рекомендую почитать про восхождение на Килиманджаро, впечатляет.

5. Shooow me

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

 

А что тебе не дает сорваться с места прямо сейчас?

 

What client wants client gets

September 23rd, 2011 Posted in Uncategorized | 1 Comment »

 

Размышлизмы, навеянные рассылками по клиентской базе.

1. Распродажи аля Groupon работают

Спасибо Групону, народ привык покупать всякую малонужную ерунду со значительной скидкой в надежде когда-нибудь воспользоваться ей. Рецепт: возьмите пару-тройку своих продуктов, которые продаются слабо,  объедините их в бандл, сделайте скидку процентов 60-80 и сделайте рассылку по списку клиентов. Для убедительности ограничьте срок действия распродажи и повесьте часы с обратным отсчетом.

Главное не увлечься и не включать продукты, которые и так хорошо продаются, залезете себе в карман. Работает как часы.

2. Повторенье - мать ученья

Любую рассылку с горячим предложением стоит повторить. Кто-то не успел купить, кто-то забыл, кто-то вообще не получил. Дайте им второй шанс. Это как потрясти яблоню еще раз. Упавшим яблокам уже все равно, а несколько новых упадет.

3. Как понимать клиентов.

Это самое интересное. Разговор с клиентом больше всего напоминает общение с женщиной. Думает одно, говорит другое, а ожидает от тебя третьего.

Клиент говорит: хочу чтобы было такое место, где люди могут обмениваться своими шаблонами.

Как это надо понимать: хочу чтобы другие люди делали шаблоны, а я их скачивал, желательно на халяву. Ну или в крайнем случае за небольшую копеечку (смотри пункт первый).

Пример из жизни. Сделали крутую фичу - редактор стилей, где можно полностью настраивать внешний вид приложения без какого-либо знаний HTML или CSS. Просто ставь галочки, выбирай опции и наслаждайся. Нужная, важная фича, делали долго и наконец выложили в открытый доступ.

Чтобы подстегнуть процесс создания иобмена стилями запустили конкурс. Нужно сделать свой стиль и прислать его нам. Сроку дали десять дней. Десять лучших стилей получают по 100 долларов каждый. В принципе не так плохо за пару часов работы.

Повторюсь, нужно просто делать то, что ты обычно делаешь, просто прислать файлы стилей на конкурс и, с большой вероятностью, получить приз.   Рассылку получают несколько десятков тысяч человек. Результат: свои работы прислали три человека. Мораль придумайте сами.

Удачных вам рассылок!

 

 

 

 

 

 

 

Лайфхак от Джерри Сейнфелда

March 3rd, 2011 Posted in Uncategorized | 2 Comments »

История от лица разработчика Брэда Исаака.

Много лет назад, когда Seinfeld еще было новым шоу, Джерри Сейнфелд разъезжал с концертами по стране. В то время я тусовался по клубам, пробуя свои силы как стэндап комик. Одним вечером я был в клубе, где выступал Сейнфелд. Мне удалось его перехватить до выхода на сцену и я спросил, есть ли у него какой-нибудь совет для начинающего комика.

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

Нужно купить и сделать самому большой настенный календарь на целый год и повесить его на видном месте. Вооружиться большим красным маркером.

Каждый день, когда задача выполнена, нужно отмечать этот день жирным красным крестом. Через несколько дней крестики выстраиваются в цепочку. Продолжай заниматься этим и цепочка будет расти. Тебе будет приятно на нее смотреть, особенно если продержаться несколько недель. Все что от тебя требуется - не разорвать эту цепочку.

"Не разорви цепочку", повторил он еще раз.

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

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

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

Не разорви цепочку!

Источник: Lifehacker

------------------------------

От себя - отличная идея. Осталось придумать, чем бы стоило заниматься каждый день. Писать в блог - нет столько тем, да и неинтересно. Выходить на пробежку каждый день - лениво. Может начать книгу писать?

Ссылки

Печально известный финансовый стартап Wesabe выложил исходники своего парсера сайтов банков и других финансовых организаций на Github. Вот тут немного дополнительной информации и обсуждение.

12 уязвимостей веб-приложений о которых должен знать каждый разработчик

February 25th, 2011 Posted in Технологии | 21 Comments »

Черновик статьи о типовых уязвимостях веб-приложений. Дайте знать если что-то упустил или где-то ошибся.

------------------------

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

Большинство примеров кода не привязаны к какому-либо конкретному языку программирования, но для наглядности я буду использовать PHP.

Итак, поехали.

1. SQL injection

Допустим у вас есть вебсайт с формой ввода имени пользователя. Для проверки наличия имени в базе данных  вы используте вот такой код:

$query = "SELECT * FROM `Users` WHERE UserName='" . $_POST["Username"]. "'";
mysql_query($query);

где $_POST["Username"] - введенное пользователем имя.

Пользователю достаточно ввести вот такое значение в поле Username

' or '1'='1

чтобы получился запрос, который всегда возвращает данные:

SELECT * FROM `Users` WHERE UserName = '' OR '1'='1'

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

Пример такого ввода:

a';DROP TABLE `Users`; SELECT * FROM `userinfo` WHERE 't' = 't

Запрос на выходе:

SELECT * FROM `Users` WHERE `UserName` = 'a';DROP TABLE `Users`; SELECT * FROM `userinfo` WHERE 't' = 't'

Два основных способа избежать SQL injection:

  • параметризованные запросы

Наиболее надежный метод, но не всегда подходит. В PHP можно для этой цели использовать MySQLi

$stmt = $db->prepare('update people set name = ? where id = ?');
$stmt->bind_param('si',$name,$id);
$stmt->execute();
  • escaping

В PHP для этого есть функция mysql_real_escape_string, которая заменит опасные символы на escape последовательности. Наш пример теперь будет выглядеть вот так:

$query = sprintf("SELECT * FROM `Users` WHERE UserName='%s'",
                  mysql_real_escape_string($_POST["Username"]));
mysql_query($query);
 

2. Сross Site Scripting (XSS)

XSS уязвимости могут быть подвержены динамические вебсайты, где пользователи вводят какие-то свои данные, которые потом будут показаны на странице: форумы, гостевые книги, комментарии блогам и другое. Идея XSS заключается во встраивании в текст комментария какого-то Javascript кода, который исполнится, когда страницу откроет другой пользователь.

Чем может навредить безобидный джаваскрипт? Довольно многим, от открытие левых сайтов в попапе или простого завешивания браузера до воровства куки. Последнее уже может привести к выполнению другим пользователем действий на этом сайте от вашего имени. Рассмотрим минимальный пример.

Форма для ввода текста:

 
<form id="myFrom" action="showResults.php" method="post">
<div><textarea name="myText" rows="4" cols="30"></textarea>
<input type="submit" value="Submit" name="submit" /></div>
</form>
 

Файл showResults.php:

echo("You typed this:");
echo($_POST['myText']);

Мы видим, что введенный текст никак не обрабатывается и выводится на страницу в исходном виде. Теперь рассмотрим такой пример ввода:

<script type="text/javascript">myRef = window.open('http://www.google.com','mywin',
'left=20,top=20,width=700,height=500,toolbar=1,resizable=0');</script>

Нетрудно видеть, что javascript код исполнится после сабмита формы. Лечится пропусканием ввода через htmlentities() непосредственно перед показом:

echo("You typed this:");
echo(htmlentities($_POST['myText']));

3. Использование HTTPS

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

4. Предотвращения скачивания пользовательских файлов по прямой ссылке

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

Есть закачивать все файлы в директорию вида public_html/files, то файл mysecretdoc.pdf будет доступен любому желающему по прямой ссылке http://mysecurewebsite.com/files/mysecretdoc.pdf.

Есть как минимум два способа предотвратить эту ситуацию:

  • вынеcти директорию files на уровень выше, чтобы она была вне корня вебсайта и не была доступна через веб
  • использовать .htaccess для запрета прямого скачивания

5. Пароли пользователей

- Не хранить пароли открытым текстом

Достаточно очевидное решение. Если мы будем хранить хэши паролей (MD5+salt), последстивия утечки таблицы паролей становятся намного менее серьезными, особенно в сочетании со следующим пунктом.

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

- Использовать комбинацию пароля (пин-кода) и устройства типа RSA токена для логина. Подойдет для банковских или внутрикорпоративных приложений.

- Сделать авторизацию через сторонний сервис, такой как Facebook, Twitter или OpenID. Пусть у них болит голова как уберечь пароли.

6. Шифрование и обфускация кода

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

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

Шифрование кода для PHP: ionCube, ZendGuard, SourceGuardian

Обфускация: Thicket Obfuscator for PHP

7. Шифрование данных

Шифрование данных защищает от ситуации, когда база данных попала в чужие руки, но нет кода, который с ней работает.

Технически ничего сложного здесь нет. Шифрование/декодирование можно реализвать как средствами языка программирования так и в самой БД. Второй метод предпочтительнее, особенно если нужно реализовать поиск по зашифрованным данным.

Вот как это можно сделать для MySQL.

Шифрование с помощью триггеров

delimiter |
 
CREATE TRIGGER insert_encrypt BEFORE INSERT ON cars
  FOR EACH ROW BEGIN
    SET NEW.Model = AES_ENCRYPT(NEW.Model,"my passphrase");
  END;
|
 
delimiter |
 
CREATE TRIGGER update_encrypt BEFORE UPDATE ON cars
  FOR EACH ROW BEGIN
    SET NEW.Model = AES_ENCRYPT(NEW.Model,"my passphrase");
  END;
|

Декодирование в SQL запросе

SELECT
...
AES_DECRYPT(Model,"my passphrase"),
...
FROM carscars

Бонус для параноиков

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

Из минусов:
- при смене пароля придется перешифровать данные
- в случае утери пароля восстановить данные не получится

8. Защита данных сессии (PHP, shared server)

В случае, когда ваше приложение хостится вместе с сотней других на одном сервере, кто-то может получить доступ ко всему серверу и прочитать или подделать переменные сессии.

Содержание типичного файла сессии PHP:

userName|s:5:"admin";accountNumber|s:9:"123456789";

Решение:
- шифровать переменные сессии
- хранить данные сессии в БД. В PHP можно переопределить обработчик сессии с помощью функции session_set_save_handler

9. Отключите показ сообщений об ошибках

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

Как минимум, сообщения об ошибках стоит отключить. В PHP это можно сделать вот так:

error_reporting(0);
@ini_set('display_errors', 0);

Наиболее же правильный метод это перехват сообщений об ошибке, запись их в БД, отправка уведомления разработчику итд. В PHP перехват сообщений об шибках делается с помощью функции set_error_handler(). И вот еще пример перехвата фатальных ошибок, которые нельзя перехватить с помощью set_error_handler().

10. Защитите соединение между базой данных и приложением

Применимо к ситуации когда база данных расположена на другом сервере. Вот статья, которая рассказывает как создать SSL тоннель между MySQL и PHP.

11. Защита от form spoofing

Допустим у вас есть форма редактирования данных пользователя вот с таким УРЛ: http://example.com/edit_user.php?id=12345. Ничто не мешает пользователю 12345 поменять номер аккаунта в УРЛ и попытаться отредактировать другого пользователя. Простая проверка на стороне сервера пресекает эти попытки на корню.

Неискушенный прграммист может подумать, что заменив GET на POST мы избавимся от номеров аккаунтов в УРЛ и закроем уязвимость. Разумеется это не так. Сохранив страницу на свой компьютер и изменив данные формы, злоумышленник может подделать POST запрос.

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

Эта тема плотно перекликается с валидацией всех данных, вводимых пользователем. Допустим у вас есть радио-кнопка с выбором пола.

 
<input name="gender" type="radio" value="m" />Male
<input name="gender" type="radio" value="f" />Female

Зная, что значение этого поля может быть только m или f, программист может посчитать проверку этого поля необязательным и записать его в базу данных в виде как оно есть.

Злоумышленник может сохранить эту страницу себе на диск и поменять ее следующим образом.

 
<input name="gender" type="text" value="m';DROP TABLE `Users`; ... " />

Даже если вы обработаете ввод с помощью mysql_real_escape_string(), значение все равно получится слишком длинным для односимвольного поля и поломает запрос (вот для чего мы советуем отключать сообщения об ошибках в продакшен версии).

Хорошим решением будет усечение этого поля до одного символа:

substr($_POST['gender'],0,1)

12. Cross-site request forgery (CSRF)

Эта уязвимость менее известна чем XSS, хотя не менее опасна. Представим себе форум, где участник Vasya постит сообщние, содержащее вот такой вот код:

<img src="http://mysecurebank.com/withdraw?account=petya&amp;amount=1000000&amp;for=vasya" />

Когда эту страницу откроет участник Petya, браузер исполнит запрос

http://mysecurebank.com/withdraw?account=petya&amount=1000000&for=vasya

Проблема в том, что если банк хранит данные доступа в куках, Petya будет залогинен автоматически и транзакция совершится от его имени, о чем он, конечно, и не подозревает.

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

 
<form id="f" action="http://mysecurebank.com/withdraw" method="post">
<input name="account" value="petya" />
<input name="amount" value="1000000" />
<input name="for" value="vasya" />
    </form>
 

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

Как с этим бороться?

  • проверять значение HTTP реферера. Должно быть всегда с вашего собственного вебсайта. К сожалению положиться на это дело полностбю нельзя, так как многие прокси сервера могут его не передавать. К тому же его не так сложно подделать.
  • использовать скрытое поле в форме с секретным значением, как правило привязанным к сессии пользователя. Злоумышленник не может прочитать форму от имени Пети, поэтому секретное значение окажется для него неизвестным (XmlHttpRequest не может выполнить запрос к другому серверу).
  • Дополнительно отправлять куки через форму (прочитать с помощью джаваскрипта и вставить в форму). Если куки переданные через форму не совпадают с куками из заголовка - транзакцию не проводить.
  • Ограничение времени жизни кук

Дополнительная информация:
http://en.wikipedia.org/wiki/Cross-site_request_forgery
http://www.codinghorror.com/blog/2008/09/cross-site-request-forgeries-and-you.html

Заключение

Теперь хорошие новости. От большинства этих уязвимостей несложно защититься. Многие PHP фреймворки (Yii, CakePHP, CodeIgniter, Zend, Symfony) и генераторы кода (PHPRunner) имеют встроенную защиту от большиства уязвимостей. Тем не менее, стоит понимать, как оно работает, чем чревато и как защититься. Предупрежден - значит вооружен.