PDA

View Full Version : حرفه ای: پیاده سازی سیستم لاگین امن از ابتدا تا انتها



***BiDaK***
جمعه 09 آبان 1393, 00:22 صبح
سلام.
انشالله میخوام سیستم لاگینی با امنیت خوب از ابتدا تا انتها پیاده سازی کنم.خودم یه سری تحقیقات داشتم و یه سری اسکریپتها هم دیدم , بخش دیگشم بچه هایی که تجربه ی این کارو داشتن کمک کنن تا همه بتونیم استفاده کنیم. شاید تجربه خوبی باشه.
=======================
1. پسورد
* طول پسورد حداقل در نظر گرفته بشه.(مثلا 8 تا)
* حداقل چند حرف بزرگ و حداقل تعدادی حروف کوچک بهمراه عدد.
* الگوریتم هش:
استفاده از salt رندوم و ذخیره در دیتابیس.از pepper هم میتونیم استفاده کنیم که یک رشته ثابت هم توو کد داشته باشیم.

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTE_SIZE", 32);
define("PBKDF2_HASH_BYTE_SIZE", 32);


define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);


class Hash
{
public static function create_hash($password)
{
// format: algorithm:iterations:salt:hash
$salt = self::urand();
return array(
'hash' => PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" . $salt . ":" .
base64_encode(self::pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTE_SIZE,
true
)),
'salt' => $salt
);
}


public static function urand()
{
return base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTE_SI ZE, MCRYPT_DEV_URANDOM));
}


public static function validate_password($password, $correct_hash)
{
$params = explode(":", $correct_hash);
if(count($params) < HASH_SECTIONS)
return false;
$pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
return self::slow_equals(
$pbkdf2,
self::pbkdf2(
$params[HASH_ALGORITHM_INDEX],
$password,
$params[HASH_SALT_INDEX],
(int)$params[HASH_ITERATION_INDEX],
strlen($pbkdf2),
true
)
);
}


// Compares two strings $a and $b in length-constant time.
private static function slow_equals($a, $b)
{
$diff = strlen($a) ^ strlen($b);
for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
{
$diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0;
}


/*
* PBKDF2 key derivation function as defined by RSA's PKCS #5: (https://crackstation.net/hashing-security.htm)https://www.ietf.org/rfc/rfc2898.txt
* $algorithm - The hash algorithm to use. Recommended: SHA256
* $password - The password.
* $salt - A salt that is unique to the password.
* $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
* $key_length - The length of the derived key in bytes.
* $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
* Returns: A $key_length-byte key derived from the password and salt.
*
* Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
*
* This implementation of PBKDF2 was originally created by https://defuse.ca
* With improvements by http://www.variations-of-shadow.com
*/
public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
if($count <= 0 || $key_length <= 0)
trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);


if (function_exists("hash_pbkdf2"))
{
// The output length is in NIBBLES (4-bits) if $raw_output is false!
if (!$raw_output)
{
$key_length = $key_length * 2;
}
return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
}


$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);


$output = "";
for($i = 1; $i <= $block_count; $i++)
{
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++)
{
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}


if($raw_output)
return substr($output, 0, $key_length);
else
return bin2hex(substr($output, 0, $key_length));
}
}

منیع (https://crackstation.net/hashing-security.htm)
* چطوره قبل از سند پسورد با جاوااسکریپت یک بار هش بشه؟این کد (http://anandam.name/pbkdf2/pbkdf2.js.txt)چطوره؟

2. رشته رندوم
* یه کلاس واسه توکن درست کرده بودم این چطوره؟

class Token
{
private function __construct() { }


public static function generate()
{
return $_SESSION['token'] = self::getToken();
}


public static function check($token)
{
if (isset($_SESSION['token']) && $token === $_SESSION['token'])
{
$token = $_SESSION['token'];
unset($_SESSION['token']);
return $token;
}
return false;
}


public static function getTokenFromUrl()
{
return (isset($_GET['token']) ? $_GET['token'] : '');
}


public static function getToken()
{
$uniqid = uniqid(mt_rand(), true);
$rand = mt_rand(0, mt_getrandmax()) . microtime(true);
return Base::makeHash($uniqid, $rand);
}
}

* یا اینکه این؟ الگوریتم هش هم ازین واسه salt استفاده کرده.

public static function urand()
{
return base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTE_SI ZE, MCRYPT_DEV_URANDOM));
}


* اینو اشپیلن از سایت فک کنم phpsec گذاشته بود, اگه قبلیا تایید نشد از این استفاده کنیم:

function crypt_random($min = 0, $max = 0x7FFFFFFF)
{
if ($min == $max) {
return $min;
}


if (function_exists('openssl_random_pseudo_bytes')) {
// openssl_random_pseudo_bytes() is slow on windows per the following:
// http://stackoverflow.com/questions/1940168/openssl-random-pseudo-bytes-is-slow-php
if ((PHP_OS & "\xDF\xDF\xDF") !== 'WIN') { // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
extract(unpack('Nrandom', openssl_random_pseudo_bytes(4)));


return abs($random) % ($max - $min) + $min;
}
}


// see http://en.wikipedia.org/wiki//dev/random
static $urandom = true;
if ($urandom === true) {
// Warning's will be output unles the error suppression operator is used. Errors such as
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
$urandom = @fopen('/dev/urandom', 'rb');
}
if (!is_bool($urandom)) {
extract(unpack('Nrandom', fread($urandom, 4)));


// say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this:
// -4 % 3 + 0 = -1, even though -1 < $min
return abs($random) % ($max - $min) + $min;
}


/* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called.
Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here:


http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/


The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro:


http://svn.php.net/viewvc/php/php-src/tags/php_5_3_2/ext/standard/php_rand.h?view=markup */
if (version_compare(PHP_VERSION, '5.2.5', '<=')) {
static $seeded;
if (!isset($seeded)) {
$seeded = true;
mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF));
}
}


static $crypto;


// The CSPRNG's Yarrow and Fortuna periodically reseed. This function can be reseeded by hitting F5
// in the browser and reloading the page.


if (!isset($crypto)) {
$key = $iv = '';
for ($i = 0; $i < 8; $i++) {
$key.= pack('n', mt_rand(0, 0xFFFF));
$iv .= pack('n', mt_rand(0, 0xFFFF));
}
switch (true) {
case class_exists('Crypt_AES'):
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
break;
case class_exists('Crypt_TripleDES'):
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
break;
case class_exists('Crypt_DES'):
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
break;
case class_exists('Crypt_RC4'):
$crypto = new Crypt_RC4();
break;
default:
extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF)))));
return abs($random) % ($max - $min) + $min;
}
$crypto->setKey($key);
$crypto->setIV($iv);
$crypto->enableContinuousBuffer();
}


extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0")));
return abs($random) % ($max - $min) + $min;
}


* کلا هر کدوم که پیشنهاد شد همه جا استفاده بشه حالا واسه توکن و ....

3. محدودیت ورود:
*این محدودیت واسه ورود اشتباه باشه خوبه یا نه؟ یه مشکلیم هست یکی از یه کنار میاد همرو لاک میکنه.

4. توکن
* یک توکن امنیتی در زمان ورود کاربر در دیتابیس ثبت کنیم و در کوکی دخیره کنیم بهمراه یوزر آیدی برای استفاده از rememeber me.

5. سشن:
* در دیتابیس یا بوسیله کوکی؟!
* تنظیمات:
+ session.use_cookies (http://php.net/manual/en/session.configuration.php#ini.session.use-cookies)=On
+ session.use_only_cookies (http://php.net/manual/en/session.configuration.php#ini.session.use-only-cookies)=On
+ session.cookie_httponly (http://php.net/manual/en/session.configuration.php#ini.session.cookie-httponly)=On
+ session.cookie_secure (http://php.net/manual/en/session.configuration.php#ini.session.cookie-secure)=On
+ session.use_trans_sid (http://php.net/manual/en/session.configuration.php#ini.session.use-trans-sid)=Off
+ session.cookie_secure (http://php.net/manual/en/session.configuration.php#ini.session.cookie-secure)=On
+ session.hash_function (http://php.net/manual/en/session.configuration.php#ini.session.hash-function)="sha256"
+ session.hash_bits_per_character = 5
+ session.entropy_file = /dev/urandom
+ session.entropy_length = 512
+ تغییر نام سشن

* استفاده از session_regenerate_id
* خروج:


function destroySession() {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
session_destroy();
}


6. استفاده از تصویر امنیتی

7. آیپی ؟؟

8. کنار سیستم استفاده از شبکه های اجتماعی

=========================================

تا اینجای قضیه فعلا همین.باز چیزی دیدم اضافه میکنم.
دوستان نظر بدن در مورد الگوریتم ها و بهترین راهها و چه مسائل دیگه ای هنوز دخیلن و شاید مشکل ساز بشن. هر چی به میدونین.

eshpilen
جمعه 09 آبان 1393, 02:01 صبح
اینا که گفتی بخشی از کاره ولی واسه هرکدوم میشه یه جزوه نوشت. کلی ایده، کلی تحقیق، حاصل چند سال مطالعه و تحقیق در زمینهء امنیت و رمزنگاری، همه رو من قبلا انجام دادم، ولی شما تازه میخواید شروع کنید، نه بگم از صفر صفر، ولی از یک چهارم اول ابتدای راهی که من از آخرش اون پروژه رو شروع کردم!
منکه خیلی سعی کردم این سیستم رو درست کنم و البته خیلی پیشرفت ها هم داشتم و ایده های مختلف رو استفاده و ترکیب کردم و حتی بعضی ایده های جالب جدید خودم بهش اضافه کردم که شاید توی هیچ سیستم دیگری نباشه، ولی دست آخر وقت نکردم و اولویت نداشتم از یک جایی جلوتر برم و همونطور به حال خودش رها شد.
پروژهء من مثل پروژه طراحی یک چیز مهم و نسبت به زمان خودش واقعا پیشرفته و کامل بود، ولی باقی مونده در مرحلهء چرک نویسه و آخرین مراحل نهایی که البته کار کمی هم نیست رو طی نکرده. یعنی طرح تقریبا کامله ها، ولی توی یک مشت کاغذ مچاله و چرک نویس درج شده و بصورت یک چیزی استاندارد و رسمی و بقول معروف برای مصرف کننده نهایی درنیامده.
اگر وقت و حوصله و انگیزش رو داشتم و برنامم رو طوری درست میکردم که از نظرهای دیگه مهندسی نرم افزار هم بقدر کافی استاندارد باشه و دیگران راحت بتونن استفاده کنن، فکر میکنم واقعا در سطح جهانی مشهور میشدم چون عملا سیستم رجیستر و لاگین بازمتن کامل و حرفه ای در این حد وجود نداره تاحالا تاجاییکه بنده دیدم و خبر دارم. مشکل اینه گمان نمیره کس دیگری جز خودم هم این کار رو بکنه! واقعا هم سخته خب. برنامه یکی دیگه رو، اونم اینقدر حجیم و پیچیده، با کامنت ها و داکیومنت محدود و حداقلی، بدون شیء گرایی و استاندارد خاصی، کی میتونه بخونه و بفهمه و روش کار کنه؟
فقط فایلها و متغییرهای کانفیگ برنامهء منو که تعدادشون هم واقعا زیاده با کامنت هاشون بخونی، کلی چیز و ایده جدید یاد میگیری و متوجه میشی مسئله از چیزی که فکر میکردی چقدر گسترده تر و پیچیده تر و دشوارتره، که البته چون از روی مال من میتونی یاد بگیری کلی بهت کمک میشه چون دیگه لازم نیست اونقدر که من فکر و تحقیق کردم فکر و تحقیق کنی و وقت و انرژی بذاری تا تازه بفهمی که اصلا باید چکار کنی از کجا شروع کنی چه ویژگیها و مکانیزمها و تمهیدات و امکاناتی توش بذاری. ولی با این حال بازم کار واقعا گسترده و دشواری است.
البته من خودم باید یک بار دیگه تقریبا این پروژه رو بازنویسی کنم به گمانم! من خودم هنوز گیجم و در بعضی موارد به نتیجه تصمیم نهایی نرسیدم که بالاخره باید چکار کنم. مثلا بعضی ویژگیها و تمهیدات که از اول درنظر گرفتم ولی در عمل مشخص شد که پیاده سازی اونا خیلی دردسر و هزینه داره، نمیدونم آیا باید حذف کنم یا باشن، یا شاید هم بصورت آپشنال کنم، و شاید هم تنها در عمل و با مرور زمان و تجربهء کاربرد واقعی گسترده بشه فهمید که آیا اون ویژگیها بدردی میخورن و ارزش هزینه هاش رو داشتن یا خیر. مثلا من سعی کردم که کسی نتونه براحتی وجود نامهای کاربری یا ایمیل های خاصی رو در سیستم چک کنه؛ مثلا هکر میتونه چند بار یک نام کاربری رو با پسوردی در بخش لاگین وارد کنه ببینه سیستم چی جواب میده آیا اون نام کاربری قفل میشه یا نه، اگر قفل شد میفهمه که اون نام کاربری در سیستم وجود داره. رای اینکه شما جلوی این رو بگیرید باید در بخش لاگین دقیقا همون رفتار رو وانمود کنید که برای نامهای کاربری موجود انجام میدید، و مثلا نام کاربری رو بعد از چند تلاش قفل کنید. ولی فقط این نیست، و این مسئله به بخشهای دیگر و خیلی جزییات دیگر در برنامتون هم منتشر میشه و باید در جاهای دیگر هم کاری کنید که نشه از روی چیزی وجود یک نام کاربری در سیستم رو فهمید، وگرنه اون کارتون در بخش لاگین چندان ارزشی نخواهد داشت.
اگر نمیری این کاری رو که گفتم بکنی، یا نمیتونی کامنت انگلیسی بخونی، پس توصیه میکنم کلا بیخیال این حرفا بشی. یه چیزی ناقص درست کنی در این زمینه فقط وقت و انرژی خودت رو هدر دادی و چندان ارزشی نداره، چون امنیت خصلتش اینطوریه که همه چیز و همه جهات باید با هم بالا بره و به یک سطح برسه، وگرنه مثل یک ساختمون میمونه که درب اون مثل درب امنیتی گاوصندوق باشه ولی پنجره هاش معمولی باشه و حفاظ نداشته باشه!
البته بنده تقریبا شکی ندارم که اینطور حرفها و تاپیک ها هم جدی نمیشه گرفت و مثل هزاران مورد و اعلام پروژه ای هست که با سر و صدا و ادعا شروع شده ولی دست آخر خیلی زود به حال خودشون رها میشن و کسی صداش هم درنمیاد :متعجب:
ولی از نظر سرگرمی و بحث و تئوریکش بنظر من بحث و موضوع خوبیه و خواستی در حد وقت و توان در خدمتت هستیم.
یه نظر رک و خشانت بار ولی صداقانه و عاقلانه میدم و اون اینکه الان شما هنوز در مرحله و صلاحیتی نیستید که بشه برای این کارها روی خودتون حساب کنید و جدی گرفته بشید، و کد و برنامه هایی هم که درست کنید (تازه اگر تا اونجا دوام بیارید و پای حرفتون وایسید) بیشتر اسباب بازی و سرگرمی و سر و صدای توخالیه تا چیز دیگه.
الان شما در مرحلهء یادگیری و تئوری هستید صرفا. و نهایت مثلا برید روی یک بخش خاص مثلا بگید من یک تابع رندوم امنیتی یا هش امنیتی طراحی و درست میکنم (یا بصورت شیء گرا و کلاس مثلا). همین دوتا که گفتم خودش کلی سواد و تحقیق میخواد. البته بنده قبلا تقریبا تمام این موارد رو انجام دادم و نتایجش رو هم منتشر کردم، ولی انجام و تحلیل مجددش توسط دیگران هم میتونه آموزنده و مفید باشه، چون تا وقتی خودتون همه چیز رو ندونید و درک نکنید نمیتونید از امنیت برنامه هاتون اطمینان خوبی داشته باشید. اینکه چندتا کد و کتابخانه و دستورالعمل آماده موجود باشه، خیلی مسائل و موارد رو حل نمیکنه. در یک بحثی که با مهندس دربارهء اینطور مسائل داشتیم هم به ایشون گفتم که مثلا من تابع هش درست میکنم میذارم بخاطر این نیست و برای دوتا مبتدی و حتی برنامه نویس معمولی (بدون تخصص ویژه در امور امنیتی) نمیگم که بردارید استفاده کنید و خیالتون راحت باشه، بلکه فقط میخوام نشون بدم که اصول و تئوری و درستش چطوریه و اینکه امنیت چقدر تخصصیه و چقدر جای کار داره برید یاد بگیرید اینم سرنخ و کمک. البته حرفه ایها که دنبالش باشن میتونن بردارن استفاده کنن؛ مثل خودم که میگشتم و مواردی رو پیدا میکردم و بعضا اصلاح میکردم و تغییر میدادم و بعد استفاده کردم. ولی افراد دیگه نباید فکر کنن که الان من رفتم و این مسائل رو براشون حل کردم و فقط کافیه اون کد و تابع رو بردارن و استفاده کنن و به همین راحتی واسشون خاصیت زیادی داره!

***BiDaK***
جمعه 09 آبان 1393, 02:24 صبح
پییییییییییسسسسس... خالیمون کردی که:قهقهه:
میخوام تحقیقات چندین ساله ی دوستان در زمینه ی امنیت توو این تاپیک مطرح بشه.
لاگین بالاخره مسائل مختلفی داره توو هر موضوعش اگه ریز وارد شیم میشه تجارب خوبی کسب کرد.
سیستم لاگینتو (http://hamidreza-mz2.tk/?p=969) میبینمش و ادامه میدم تاپیکو.:متعجب:

eshpilen
جمعه 09 آبان 1393, 02:45 صبح
اوه راستی فقط بحث امنیت هم نیست. امنیت به تنهایی در چنین سیستمی به چه دردی میخوره؟ باید امکانات و انعطافش هم کامل باشه.
تقریبا هر چیزی و هر سیستمی هم توش میذاری باید تا حد ممکن قابل کانفیگ باشه. مثلا سیستم قفل میذاری که بعد از تعدادی تلاش اشتباه امکان لاگین به اکانت رو قفل کنه، خودت داری میگی ممکنه کسی از همین سوء استفاده کنه و اکانتها رو زرت و زرت قفل کنه، و بله درسته، واسه همین این سیستم باید کانفیگ کاملی داشته باشه و علاوه بر اینکه بشه دفعات و زمان رو براحتی تغییر داد، بشه کلا خاموشش کرد، و بشه تنها برای کاربران خاصی خاموشش کرد، یا حداقل کانفیگ های ادمین در این زمینه باید از کاربران دیگه کاملا جدا باشه، باید امکان این رو هم بذاری که بعد از یک تعداد مشخصی تلاش (که طبیعتا اونم قابل تنظیمه) و قبل از اینکه قفل بشه کپچا بیاد چون این کار میتونه جلوی قفل شدن بی مورد یا عمدی اکانتها بخصوص توسط روبات ها رو بگیره، دیگه جونم برات بگه که شما باید دو نوع قفل داشته باشی نه یکی، یک قفل بر اساس IP و یکی دیگه بر اساس اکانت، و این دوتا تنظیماتشون کاملا از هم جداست و میشه هرکدام رو مستقل تعداد و زمانش رو تنظیم کرد، فعال یا غیرفعال کرد، تعدادی که بعدش کپچا میاد رو تنظیم کرد، بعد همهء اینا تازه یه سیستم که بنده در پروژم اسمش رو گذاشتم block-bypass باید داشته باشی که بشه از طریق ارسال یک لینک مخصوص به ایمیل بلاک رو دور زد، و این سیستم باز خودش کانفیگ داره و قابل فعال و غیرفعال سازی باشه، و ضمنا بتونی مثلا فقط برای ادمین فعالش کنی یا بعکس فقط برای کاربران معمولی، و خلاصه میبینی که همینطور سیستم در سیستم و پیچیدگی و ترکیبات کانفیگ های مختلف با هم هست که در هر حالت باید سیستم رو طراحی و پیشبینی کنی و در کدت کلی if و چک کردن ترکیب ها رو خواهی داشت که مثلا اگر فلان کانفیگ خاموش بود ولی فلان کانفیگ روشن بود و فلان اتفاق افتاد باید چطور بشه و غیره و غیره. و حالا تازه اینا فقط توضیحات کلی و اولیه بود. جزییات هست، تست هست، مسائل جانبی هست.
همین یک سیستم قفل که گفتی دیدی چقدر گسترده و پیچیده است و چقدر ابعاد داره! حالا شما چطوری میخواستی پیادش کنی؟
تمام این مواردی رو که گفتم بنده در پروژم درنظر گرفتم و پیاده کردم. یه چیزایی گذاشتم توش اصلا تاحالا کسی بهش فکر هم نکرده. مثلا سیستم گذاشتم که هر کاربری بتونه تنظیمات سیستمهای قفل مربوط به اکانت خودش رو تعیین کنه (اینکه قفل IP و اکانت کدومش فعال یا غیرفعال باشه برای اکانت خودش)، کانفیگ گذاشتم که بتونی تعیین کنی کاربران حق دارن کدوم این تنظیمات رو برای اکانت خودشون دستکاری بکنن، بعد ببین تازه حساب کجای کار رو کردم، حساب این رو کردم که مثلا در تنظیمات اصلی ادمین سیستم بلاک رو مثلا بلاک اکانت و بلاک IP رو روشن تعیین کرده، کاربر میاد تنظیم میکنه واسه اکانت خودش که فقط بلاک اکانت روشن باشه (بلاک بر اساس IP خاموش)، بعدا ادمین میاد و در فایل کانفیگ اصلی/سراسری بلاک اکانت رو غیرفعال میکنه، اونوقت آیا درسته که اکانت طرف بدون محافظت بمونه؟ میگم نه، باید بلاک بر اساس IP رو براش بطور خودکار روشن کرد، چرا؟ ولش کن الان خودم خداییش یادم نیست دقیقا و باید کدم رو دوباره مرور کنم تا یادم بیاد چی به چی بود! فقط همینو بگم که موقعی که کاربر تنظیم سیستم بلاک واسه اکانت خودش رو تغییر میده، تنظیمات سراسری سیستم بلاک در اون زمان هم در رکوردش در دیتابیس ذخیره میشه تا بعدا سیستم بتونه از روش بفهمه و تصمیم بگیره که در اون زمان سطح امنیت چی بوده و بعدا چی شده چطور شده آیا امنیت مفروض کابر بر اثر تغییرات تنظیمات اصلی سیستم بلاک توسط ادمین پایین اومده یا خیر و باید چه کرد و سیستم خودش بصورت خودکار دوباره سطح امنیت رو به نزدیکترین سطح به سطح مورد نظر کاربر برگردونه. من خودم الان جزییات این الگوریتم رو یادم نیستم ولی یادمه روش کلی کار کردم و کار راحتی نبود.
یعنی ببین حساب کجا رو باید بکنی اگر بخوای حرفه ای عمل کنی بخصوص در بحث امنیت. باید حساب کنی اگر کاربر یک کانفیگی داشته و بعدا ادمین اومده توی سایت یه تغییراتی داده سر اون کانفیگ و تنظیمات کاربر بدون اطلاعش چی میاد و باید چه کرد! حالا این نیاز و پیچیدگی افزوده از کجا اضافه شد اصلا؟ از اونجا که شما این سیستم رو پیاده کردی و به کاربران اجازه دادی بتونن تنظیم جداگانه برای سیستم بلاک اکانت خودشون داشته باشن؟ بعد خب چرا، چرا چنین اجازه ای دادی و این زحمت رو به خودت دادی کار رو اینقدر حجیم و پیچیده کردی توی کدوم برنامه ای مگر همچین چیزی دیدی؟ بخاطر اینکه فرضا یک کاربر خاص به علت خاص مورد سوء استفاده و بلاک اکانت مکرر قرار میگیره، ولی دیگران که اینطور نیست براشون، کاربر میتونه سیستم بلاک رو برای خودش غیرفعال کنه، شاید اصلا پسوردش اینقدر قوی هست که از حملهء Brute-force خیالش هم نیست، خب پس میتونه سیستم بلاک رو خاموش کنه و هکر رو سر کار بذاره، ولی یوقت شاید ما فکر کنیم یا تجربه نشون بده که نباید چنین اختیاراتی رو به کاربران داد و اشتباه میکنن یا جور دیگه دردسر واسه خودمون میشه، پس شما باید کانفیگ غیرفعال کردن این قضیه رو توی سیستم خودت داشته باشی، اما ادمین که همیشه باید به این امکان دسترسی داشته باشه بهرحال چون ادمینه!
آقا جزییات، جزییات، ترکیب، ترکیب، پیچیدگی، ... اینا که گفتم تازه سردر قضیه است و کدنویسی و تست تمام حالات یک قضیه دیگه. توی کدنویسی هم باز جزییات بیشتری پیش میاد و مواردی که احتمالا به ذهنتون نمیرسه.

بذار بازم بیشتر بگم تا بدونی واقعا چقدر سطح و جزییات هست در برنامه نویسی و چقدر پیچیدگی و نکاتی که کمتر کسی حتی به فکرش خطور کرده.
مثلا همین سیستمهای بلاک در حالت کلی چطور کار میکنن الگوریتم و مکانیزمش چطوریه؟ اینطوریه که طرف یه فیلد میذاره توی جدول، مقدارش اول صفره، خب، بعد یک تلاش لاگین ناموفق، یکی به مقدارش اضافه میکنه، همزمان زمان اون تلاش لاگین رو هم توی یک فیلد دیگه آپدیت میکنه، یه تلاش لاگین ناموفق دیگه صورت میگیره، چک میکنه ببینه از زمان تلاش ناموفق قبلی آیا 15 دقیقه گذشته یا نه، اگر نگذشته بود یکی دیگه به مقدار شمارش تلاشهای ناموفق اضافه میکنه، اگر گذشته بود باید مقدار فیلد رو مجددا به 1 ریست کنه، ... . تعداد تلاشهای لاگین ناموفق که به تعداد تعیین شده رسید، اکانت رو برای مدت معینی میبنده.
بگو ببینم الان این الگوریتم بنظر شما مشکلی نداره؟
در سری برنامه های بعدی بهتون میگم همین الگوریتم که بیشتر افراد ازش استفاده میکنن یه اشکالی داره (البته قبلا گفتم بازم میگم حالا :لبخند:)

eshpilen
جمعه 09 آبان 1393, 03:03 صبح
بعد شما باید امکانات لاگ امنیتی و ارسال هشدار و خبر کردن ادمین هم در برنامت بذاری.
حالا این باز خودش کلی جزییات داره.
امکان این رو بذاری با ایمیل یا موقع مراجعه ادمین رو از حمله آگاه کنی.
حالا کدوم حمله؟ با چه پارامترهایی؟ اگر یهو سیستم مورد حمله گسترده واقع شد همینطوری زرت و زرت ایمیل ارسال نشه دهن ادمین سرویس بشه ایمیلش بترکه و غیره. پس واسه همهء اینا باید تمهید کنی و کانفیگ و کد هوشمند بذاری.
توی برنامه من میای مثلا تعیین میکنی که اگر در زمان x تعداد y اکانت در سیستم مورد حمله قرار گرفت به ادمین ایمیل هشدار ارسال کن که بدونه سایت مثلا توسط یک botnet یا چیز دیگه مورد حمله جدی قرار گرفته. ولی باز باید یه کانفیگ هم بذاری که اکانت خود ادمین حتی اگر یک بار بهش حمله شد خبر بشه! البته اینم اختیاری (قابل خاموش و روشن کردن). بعد تازه میتونی این سیستم هشدار رو برای کاربران معمولی هم بذاری که اگر به اکانتشون حمله شد خبر بشن و شاید فکری و کاری بکنن (این یکی رو من در سیستمم نذاشتم دیگه نمیدونم یادم نبود یا به هر علتی فکر کردم بقدر کافی مهم نیست).
بعد مثلا حمله رو از حالات طبیعی چطور میشه تشخیص داد؟ مثلا شما میگی من هزارتا کاربر دارم اگر در 12 ساعت بیشتر از 20 تا اکانت قفل شد غیر عادیه وگرنه باید فرض کرد خود بعضی کاربران بودن که به هر علتی پسوردشون رو چند بار اشتباه زدن و اکانتشون قفل شده در نتیجه. ولی این 20 تا رو شما از کجا آوردی اگر تعداد اکانتهای سیستم شما رشد کرد و از هزارتا رسید به 100 هزارتا اونوقت میخوای دوباره تغییرش بدی؟ یک راهش که من امکانش رو توی برنامم گذاشتم اینه که این تعداد رو بصورت درصدی بدی، یعنی بگی مثلا اگر در 12 ساعت 2% از اکانتهای سیستم بلاک شد اونوقت به من خبر بده.
کانفیگ گذاشتم واسه اینکه بتونی تعیین کنی حداقل فاصله زمانی بین ارسال دو ایمیل هشدار چقدر باشه.
کانفیگ دیگه داریم واسه اینکه تعیین کنی در زمان x حداکثر چند ایمیل بتونه ارسال بشه (این با قبلی فرق میکنه - هرکدوم دلیل ظریف و کاربرد خاص خودش رو داره).
کانفیگ گذاشتم که ... بیخیال دیگه!
خب واسه امشب تا اینجا فکر کنم کافی باشه. فعلا همینا رو بخونید روش فکر کنید سرتون گیج میره :لبخندساده:
آه راستی یه مورد مربوط دیگه یادم رفت :لبخند:
شما باید برای حداکثر تعداد رکوردهای درج شده در جدول هات بخاطر حجم دیتابیس هم سیستم نظارت و پاکسازی قابل تنظیم بذاری که نذاری همینطوری بی رویه هرچقدر رکورد در جدولهای لاگ و اینها درج بشه و رکوردهای اضافه و قدیمی رو درصورت لزوم بصورت خودکار حذف کنی، چون این مسئله خودش ممکنه در بعضی حملات DOS با هدف پر کردن دیتابیس و فضای محدود هاست و بنابراین از کار افتادن یا معیوب شدن کارکرد سایت (بخصوص کارکردهای امنیتی این وسط واسه ما مهمتر هستن) استفاده بشه یا اصلا غیرعمدی و بعد از یه زمان طولانی یا در زمان کوتاهتری مثلا در زمان حملهء گسترده و botnet و این حرفا به سایت اتفاق بیفته.
البته این مورد شاید خیلی هم مهم نباشه، ولی من فکر کردم بهرحال بهتره در یک سیستم پیشرفته و کامل و امنیتی چنین امکانی هم موجود باشه.

eshpilen
جمعه 09 آبان 1393, 03:28 صبح
حالا تازه به بخش ثبت نام نرسیدیم هنوز :لبخند:
شما همش میگی لاگین لاگین، بخش ثبت نام نداری یعنی یا اینکه دست کم گرفتی؟
میخوای باز کلی جزییات و سیستم روی دستت بذارم که توش غرق بشی؟ :لبخند:
همون ایجکس که شما باهاش آزاد بودن نام کاربری انتخاب شده رو در فرم ثبت نام چک میکنی مسئلهء امنیتی داره اگر بخوایم واقعا حرفه ای و دقیق عمل کنیم، و شما باید براش الگوریتم و محدودیت و امکان تنظیم بذاری. هرکس همینطوری نباید بتونه بیاد توی فرم ثبت نام شما و زرت و زرت سه سوت نامهای کاربری مختلف رو وارد کنه ببینه کدوم توی سیستم هست یا نیست! سیستم اگر بخواد حرفه ای باشه باید شرایط و نیازهای خاص تر از دوتا فروم و سایت عمومی و درپیت و کم اهمیت رو هم درنظر بگیره و جواب بده. یوقت یه جایی هست که اطلاعات داخل سیستم به بیرون همینطوری و به این راحتی درز نمیکنه و مثلا مثل این فروم نیست که نامهای کاربری ما توی تاپیک ها و همه جا در دسترس عموم باشه، بنابراین سیستم شما نباید براحتی یه دروازه برای نشت این اطلاعات بشه! باید ایجکس رو بشه غیرفعال کرد، محدودیت تعداد چک روش گذاشت، کپچا بذاری فرم ثبت نام طرف حتما مجبور بشه برای تکرار عملیات کپچا رد کنه (هم برای محافظت از نامهای کاربری سیستم و هم برای محافظت از آدرسهای ایمیل)، جلوی تست و جمع آوری اطلاعات با روبات ها رو بگیری.

اوه راستی یکی از امکانات جالب دیگری که سیستم من داره اینه که (البته مربوط به بخش لاگین میشه) ... ولش کن الان خسته شدم و واسه امشب هم کافیه. اصلا من باید یه تاپیک بزنم و انبوه امکانات و تمهیدات برنامم رو توش لیست کنم و توضیحاتم رو اونجا بدم مثل اینکه!

***BiDaK***
جمعه 09 آبان 1393, 14:55 عصر
خوب از ابتدا یه سری چیزا توو ذهنم بود.
سیستم نقش ها بهش اضافه بشه.
تمام کانفیگ بصورت graphical ادمین تعیین کنه.چون یوقتهایی هست واسه سایتی شاید نیاز نباشه تمام این جوانب در نظر گرفته بشه و نیاز به یک لاگین ساده و سبک داشته باشه و از جداول کمتری استفاده بشه.
یک سری متد هم باید در نظر گرفته بشه که در داک معرفی بشه واسه استفاده ی کاربر توو پروژش و ...
سیستم رجیستر داره که اونو مرحله ی آخر گذاشته بودم.:قهقهه:
این پروژه فسفر زیادی ازم میسوزونه:قهقهه: مدتی هم طول میکشه ولی اگر به نتیجه برسه تجربه ی خوبی میشه واسم.
هر نکته ای توو قالب پروژه باشه شاید بیشتر اثر داشته باشه.
امکانات سیستمو خوب همینجا بزار.بی ربطم نیست به موضوع.همه ی مطالب یکجا جمع میشه.

eshpilen
شنبه 10 آبان 1393, 20:52 عصر
باشه به مرور که فرصت میکنم از روی متغییرهای کانفیگ پروژه خودم براتون نکات جالب رو میگم. تازه توی کد هم فکر کنم خیلی مسائل باشه که با مرور مجدد کدهام یادم بیاد، ولی فکر نمیکنم وقت و حوصلش رو داشته باشم.

راستی گفتی سیستم نقش و اینترفیس کانفیگ گرافیکی.
این پروژه اگر بخواد واقعا کامل و امن باشه و تمام نکات مهمی رو که گفتم رعایت کنه، خودش بقدر کافی بزرگ و پیچیده هست. بخاطر همین من از ابتدا میدونستم و از اجزای غیرضروری مثل سیستم نقش و اینترفیس گرافیکی برای تنظیمات صرفنظر کردم.
ضمنا سیستم role و permission و اینها یه چیزی هست که بنظرم میتونه جدای از خود سیستم رجیستر و لاگین تلقی بشه و لزومی نداره حتما جزیی درونی از اون باشه. یعنی میشه بصورت یک افزوده و کدها و سیستم جداگانه درستش کرد. کاری نداره خب شما چندتا جدول اضافه میذاری در کد و برنامه خودت و سیستم نقش رو توی این پیاده میکنی و با سیستم لاگین هویت و user id طرف رو تشخیص میدی و بعد توی سیستم و جدولهای نقش خودت role و پرمیشن های نگاشت شده برای اون کاربر رو استخراج میکنی.
ضمن اینکه سیستم نقش فکر کنم به چند مدل طراحی و پیاده میکنن و لزوما اگر یه چیزی محدود و ثابت و طبق نظر خودت درست کنی ممکنه برای همه کس و همه جا و همه کاری مناسب و قابل قبول نباشه، مگر اینکه خیلی منعطف و قابل گسترش طراحیش کنی که مثلا طرف هر گروه و role ای خواست بتونه اضافه کنه و بعد به همین شکل سیستم پرمیشن قابل گسترش هم داشته باشه که اگر خواست از پرمیشن هم استفاده کنه و برای هر کاربر و همچنین گروه/role پرمیشن های جزیی تعریف کنه بتونه. خب این خودش بنظرم کار کمی نیست و میتونه یک زیر پروژه باشه یا حتی یک پروژهء جداگانه.

درمورد اینترفیس کانفیگ گرافیکی گفتی یه چیزی که بنظرم رسید اینکه اصولا بین وبمستر/مالک اصلی که برنامه رو نصب و راه اندازی میکنه و ادمین سیستم میتونه تفاوت باشه و دو فرد و نقش جداگانه باشن که نیاز به سطوح دسترسی جداگانه داشته باشن. پس باید اینم توسط همون وبمستر بتونه قابل تنظیم باشه که نقش ادمین آیا بتونه و کدام تنظیمات رو تغییر بده یا نده (و شاید اینکه از یک تنظیم هم فقط بعضی حالاتش و نه تمام حالات رو بتونه انتخاب کنه - شاید این باز خودش داستان بشه و حجم و پیچیدگی برنامه رو زیادتر کنه).

eshpilen
شنبه 10 آبان 1393, 21:11 عصر
خب از روی متغییرهای کانفیگ برنامم همینطوری نکاتی رو میگم و میرم سراغ بعدی.

یک چیزی که باید توی برنامه پیاده کنید اینه که یکسری عملیات مهم توسط ادمین انجام میشن طبیعتا، مثلا تایید یا رد یک ثبت نام معلق یا حذف یک اکانت، اینها اونوقت باید یه آپشن براش بذارید که بشه تنظیم کرد انجام اینطور عملیات نیاز به ورود پسورد ادمین داشته باشه یا نه. یعنی به صرف اینکه ادمین در اون سیستم لاگین هست نباید هر عملیاتی بتونه فقط با چندتا کلیک انجام بشه! این به دلایل متعدد و سناریوهای متعددی بنظر بنده صحیح نیست. البته می باید این گزینه آپشنال باشه و بشه روشن و خاموش کرد تا بشه بنا به شرایط و صلاحدید و اهمیت کاربرد، اون رو تعیین کرد. مثلا من اگر توی خونه روی سیستم شخصی خودم لاگین هستم و مزاحم و بچه و خطری تهدید نمیکنه دسترسی به کامپیوترم رو، شاید نخوام برای انجام عملیات پسورد وارد کنم و میخوام راحت با یک کلیک هرکار میخوام بکنم و بزنم اکانت ملت رو بترکونم! شاید اگر اشتباهی هم دستم بره روی ماوس یا با کیبورد اشتباه بزنم و اکانت مردم دلیت بشه اونقدری مهم نباشه! البته این سیستم وارد کردن پسورد از نظر هکرهایی که دسترسی مستقیم و فیزیکی به سیستم هم ندارن باز اهمیت داره و میتونه درصورت نفوذ به سیستم جلوشون رو بگیره و خسارت رو کنترل کنه.

بنده توی برنامم سه مدل قابل انتخاب کردم این کانفیگ رو. یکی اینکه عملیات ادمین پسورد نخواد، یکی اینکه بخواد، سومی اینکه بخواد ولی تعیین کنیم اگر حداکثر تا X ثانیه قبل پسورد صحیح وارد شده بوده (طبیعتا در عملیات قبلی توسط ادمین)، دیگه نیازی به پسورد نباشه. مثلا اگر 1 دقیقه پیش پسورد رو وارد کرد دوباره پسورد نخواد، که این برای انجام عملیات هایی که به تعدادی ادمین میخواد با فاصلهء کم تکرار کنه میتونه مفید باشه. البته من خودم روی اصولی بودن این گزینه از نظر امنیتی شک دارم، اما بهرحال امکان اونو گذاشتم تا اگر خواستیم و مشکلی نداشت استفاده بشه. یه مسئله در طراحی چنین سیستمهایی اینه که بعضی چیزها رو اصلا نمیدونی و هرچی تحلیل و تحقیق میکنی به نتیجه و تصمیم مطمئنی نمیرسی که بالاخره درسته یا نادرسته باید باشه یا نباشه و به چه شکلی باید پیاده بشه، بخصوص که برنامه هایی در این حد گسترده و کامل و امنیتی میشه گفت تاحالا وجود نداشتن (حداقل بازمتن و در دسترس عمومی نبودن) و نمونه و الگو و تجربهء کافی و مطمئن در این موارد وجود نداره که بتونیم از اونا درس بگیریم و ازشون پیروی کنیم؛ بنابراین ما در این موارد باید بیایم و اون چیز رو بصورت یک آپشن بذاریم؛ اگر فکر میکنیم احتمال بیشتر چیز خیلی خوب یا لازمیه، باید تنظیم دیفالت رو فعال بذاریم، اگر بیشتر احتمال میدیم که عاقلانه تر اینه که بطور پیشفرض غیرفعال باشه خب همین رو دیفالت میذاریم.

eshpilen
یک شنبه 11 آبان 1393, 20:43 عصر
هرچی پروژه خودم رو بررسی میکنم بیشتر متوجه میشم که اگر روش کار کنم و به سطح نهایی برسونمش به شهرت جهانی میرسم :لبخند:
ولی من آدمی نیستم که به شهرت و اینها اهمیتی بدم. بیشتر دنبال عشق و علاقه خودمم. ولی گاهی فکر میکنم یکی پیشدستی کنه بیاد از روی من ایده بگیره/کپی کنه (یا شایدم برنامه منو ادامه بدن) و آخرش اعتبارش برای دیگران ثبت بشه :متفکر: ولی حتی در اون صورت بهرحال من به علم و بشریت خدمت کردم و برام کارمای مثبت داره :لبخند:

یک مشکل توی یه پروژه با هدف بی نقص بودن اینه که در جریان که پیش میری خیلی موارد و جزییات اضافه میشن و به فکرت میرسه و بعد نمیتونی ازشون بگذری چون هرچی جاهای دیگر پروژه و از ابعاد دیگر به کمال نزدیک تر میشه میگی حیفه فلان جاش رو هم درست نکنم، حیفه فلان جزییات و امکان و انعطاف و کانفیگ رو توش نذارم. خلاصه همینطور کار زیاد میشه. توی یه سیستم رجیستر و لاگین درپیت معمولی که بقیه درست میکنن خیلی جزییات اهمیت نداره، چون بقول معروف میگن مورچه چیه که کله پاچش چی باشه :لبخندساده:

خب دیگه سخنرانی و شیرین کاری کافیه :لبخند:

شما هر چیزی رو هرجا براش الگو میذاری و چک میکنی باید همه جاهای دیگه هم همونطور باشه. مثلا اگر میگی حداقل طول پسورد 6 کاراکتر، اینو مسلما موقع ثبت نام چک میکنی، اما چه کسی موقع تغییر پسورد یا ریست پسورد هم اینو چک میکنه؟ باید یک کانفیگ مرکزی برای این موارد داشته باشی که بعدا هرجا ازش استفاده کنی.

راستی سیستم block-bypass که قبلا گفتم توی سیستم میذاری و موقعی که اکانت بلاک میشه کاربر میتونه تقاضای دریافت لینک block-bypass بکنه که به ایمیلش ارسال میشه، بعد کاربر با لینک block-bypass میاد لاگین بکنه، باید اونجا هم محدودیت تعداد لاگین ناموفق بذاریم! به دلایل ظریف امنیتی که شاید خودمم الان حضور ذهن کافی نداشته باشم! یه کاری که باید آدم همیشه بکنه اینه که یک دفترچه یادداشت کاغذی دفتری چیزی با قلم همیشه همراهش باشه (حتی کنار تخت خوابش!) چون مدام ایده و نقص و نکته و کارهایی که باید انجام بدی بنظرت میرسه و اگر یادداشت نکنی ممکنه یادت بره این همه جزییات رو بخاطر حجم و پیچیدگیش.

یه مورد دیگه که بگم اینکه موقعی که کاربر میخواد پسوردش رو تغییر بده باید پسورد فعلیش رو هم وارد کنه ولی یه نکته ای که فکر نکنم کسی رعایت کنه اینه که باز همینطوری بدون محدودیت نباید باشه که هر تعداد خواست بتونه پسورد فعلی رو اشتباه وارد کنه! یک دلیلش اینه که فرضا یک سیستمی که کاربر لاگین هست زیر دست کس دیگه میفته بعد اون شخص ممکنه اونقدر باهوش و زیرک باشه که بیاد و از این امکان برای حدس و تست پسورد کاربر استفاده کنه (نمیتونه بطور معمول این کار رو در بخش لاگین انجام بده چون سیستم بلاک و این حرفا اونجا هست) و اینقدر پسوردهای مختلف رو تست کنه تا شاید پسورد کاربر رو پیدا کنه. حتی میشه این کار رو با یک روبات انجام داد و به این شکل تعداد زیادی پسورد رو بصورت خودکار در یک زمان معینی تست کرد و عملا حمله دیکشنری و brute-force و اینها انجام داد. ضمنا این مسئله که گفتم فقط به کسی که دسترسی مستقیم به سیستم کاربر پیدا کنه محدود نمیشه و در سناریوهای دیگری هم که هکر مثلا تونسته کوکی/توکن لاگین کاربر رو سرقت کنه میتونه امکان بدست آوردن اصل پسورد رو ازش بگیره. موقعی که طرف پسورد فعلی رو بیش از حد مجاز اشتباه وارد میکنه کلا از سیستم شوتش میکنی بیرون (از لاگین خارج میشه)، نه اینکه هنوز لاگین بمونه و بعدم بعد از یه بازه زمانی بتونه مجدد تلاش کنه. فکر کنم اینطوری از نظر امنیتی خیلی بهتر باشه و از نظر کاربری هم مشکل خاصی نیست.

eshpilen
یک شنبه 11 آبان 1393, 21:01 عصر
یه ایده و ابتکاری که بنده توی پروژه خودم بکار بردم اینه که به محض اینکه کاربر دستور logout بده، از لاگین خارج میشه، حتی اگر به اینترنت متصل نباشه، حتی اگر مرورگر روی حالت آفلاین باشه، حتی اگر سایت down باشه.
این کار امنیت لاگ آوت رو برای تمام کاربران و شرایط به شدت بالا میبره و دیگه امکان لاگین ماندن های تصادفی و بدون اطلاع کاربر که گهگاه ممکنه بخصوص برای کاربران غیرفنی یا موقعی که عجله دارن یا بهرصورت مشکل فنی در اتصال اینترنت یا سایت وجود داره، تقریبا از بین میره.
این کار رو با افزودن یک کوکی autologin اضافی که با کلیک کاربر روی گزینه خروج فورا توسط جاوااسکریپت محتویات اصلیش پاک میشه انجام دادم! بدون این کوکی کاربر توسط سیستم احراز هویت نمیشه.
البته من یک کوکی دیگر هم دارم که سمت سرور کنترل و حذف میشه و وجود اون کوکی بخاطر امنیت و یکسری مسائل دیگر لازمه. اون کوکی که سمت کلاینت با جاوااسکریپت میشه باهاش کار کرد در مقابل حمله های XSS آسیب پذیره طبیعتا و از نظر امنیتی درست نیست فقط با همون کاربر بتونه لاگین بشه. کوکی ای که سمت سرور پاک میشه با آپشن http only ست میشه که نشه با جاوااسکریپت در سمت کلاینت اون رو خوند (برای جلوگیری از سوء استفاده توسط حملات XSS).

eshpilen
یک شنبه 11 آبان 1393, 21:15 عصر
یک ایده و سیستم دیگه که توی پروژم گذاشتم، سیستم رمزنگاری سشن است. البته فکر کنم باید روش بیشتر کار کنم تا با اطلاعات سشن بقیهء برنامه ها تداخل نکنه (بخاطر اینکه احتمال تداخل وجود داشت تنظیم اون رو بصورپیشفرض غیرفعال کردم). این سیستم میاد و محتویات سشن برنامه رو با الگوریتمهای رمزنگاری قوی رمز و حفاظت میکنه که در نتیجه باعث میشه شما روی هاستهای اشتراکی از امنیت سشن خیالتون راحت باشه، حتی اگر کانفیگ ناامنی داشته باشن. هیچکس نمیتونه چنین محتویات رمزشده ای رو بخونه یا دستکاری کنه! فقط تنها کاری که یک نفوذگر ممکنه با چنین فایلهای سشن روی سرور بکنه اینه که فایلهای سشن برنامه شما رو دلیت کنه (یا محتویات اونا رو حذف/غیرقابل استفاده بکنه) و به این شکل در کارایی سایت ایجاد مشکل کنه (میشه گفت یک نوع از حملهء DOS است)، ولی بهرحال هیچ غلط دیگری نمیتونه بکنه و هیچ سرقت اطلاعات و نفوذی به اکانتهای سیستم نمیتونه انجام بده. البته بنده در این برنامه اصولا هیچگونه اطلاعات امنیتی حساسی رو که قابلیت سوء استفاده چندانی داشته باشه در سشن قرار ندادم و احراز هویت هم در برنامه بنده با سشن انجام نمیشه (با کوکی و دیتابیس کار میکنه)، ولی بهرصورت این سیستم رو هم پیاده سازی کردم بخاطر کامل بودن و اینکه بعدا شاید نیاز بشه و بخوایم اطلاعات حساس تری رو توی سشن بذاریم.
البته میدونید که برای امنیت میشه از ذخیره سشن در دیتابیس هم استفاده کرد که اون ضعف DOS رو هم نداره! شاید من فکر کردم که رمزنگاری کار کمتری میبره که سیستم دیتابیس رو پیاده نکردم. بهرحال من نمیخواستم زیاد روی این کار کنم چون برنامم استفاده گسترده و مهمی از سشن نمیکرد.

***BiDaK***
یک شنبه 11 آبان 1393, 22:56 عصر
البته من یک کوکی دیگر هم دارم که سمت سرور کنترل و حذف میشه و وجود اون کوکی بخاطر امنیت و یکسری مسائل دیگر لازمه. اون کوکی که سمت کلاینت با جاوااسکریپت میشه باهاش کار کرد در مقابل حمله های XSS آسیب پذیره طبیعتا و از نظر امنیتی درست نیست فقط با همون کاربر بتونه لاگین بشه. کوکی ای که سمت سرور پاک میشه با آپشن http only ست میشه که نشه با جاوااسکریپت در سمت کلاینت اون رو خوند (برای جلوگیری از سوء استفاده توسط حملات XSS).

توضیح بیشتر


احراز هویت هم در برنامه بنده با سشن انجام نمیشه (با کوکی و دیتابیس کار میکنه)

برنامت چی بوده؟
===============
کدها و فایلات یکم زیادو شلوغه کل ماجرا و ارتباطارو سخت میشه فهمید.بنظرم باید mvc پیادش کنم.
تا اونجایی که من فهمیدم چارچوب اصلی همون مواردی هست که گفتم توو پست اول و بقیه آپشنا واسه محکم کردم کده.
یه نکته ی دیگه , من یه جا دیدم سرور کلاستر با 25 gpu توو بروت فورس هر ثانیه 180 بیلیون پسورد md5 چک میکنه.
حالا اگه salt هم داشته باشه پسورد و اگه 8 کاراکتری باشه 10 ساعت زمان میبره.
همی پسورد هشتاییرو اگه با salt رندوم و تووی حلقه ی 1000 تایی بزاریم 124 روز.
هش pbkdf2 با الگوریتم sha512 و 1000 دور و 8 کاراکتر 700 سال.
bcrypt هم 3000 سال.
خوب اینجوری اگه یه پسورد امن طولانی تر و salt ای هم به اندازه ی طول پسورد در نظر بگیریم -md5- با دور 5000 تا خوب دیگه تا حد زیادی امنیت برقراره حالا واسه محکم کاری pbkdf2 اینطور نیست؟ یا قضیه پیچیده تره؟:لبخند:

eshpilen
یک شنبه 11 آبان 1393, 23:14 عصر
خب شما یه سشن یا کوکی محتوی یه توکن/کلید دارید برای بخاطرسپاری لاگین.
مثلا الان در سایت برنامه نویس وقتی لاگین میکنید فردا هم دوباره کامپیوتر رو روشن میکنید میاید توی سایت هنوزم لاگین هستید چطوری؟
منم در برنامم از کوکی محتوی کلید برای این کار استفاده کردم. این کلید یک رشتهء رندوم طولانی است که از همون موقع ثبت نام برای هر کاربر تولید و در رکورد اکانتش درج میشه. ولی درواقع این کلید میتونه به ازای هر بار لاگین دستی کاربر یا حتی هر درخواست، و یکسری عملیات دیگر، عوض بشه، که این برای امنیت خوبه، ولی عیبش اینه که مثلا اگر کاربر قبلا روی PC1 لاگین بوده حالا میاد روی PC2 لاگین میکنه، کلید لاگین عوض میشه و بنابراین PC1 از لاگین خودکار خارج میشه. مگر اینکه ما بیایم و یجوری یه فکری بکنیم که کاربر بتونه همزمان روی چند سیستم لاگین باشه، ولی بنده بخاطر پیچیدگی افزوده و هزینه ای که این کار داشت از این مورد صرفنظر کردم و گفتم فقط این گزینهء تغییر کلید لاگین رو بصورت قابل کانفیگ کامل میذارم، چون از طرفی فکر میکنم هر حالت دیگری بهرحال امنیت رو مقداری پایین میاره.

خب سیستم من در چندین حالت کلید لاگین رو میتونه عوض کنه. یکی موقع ورود (لاگین دستی)، یکی در هر درخواست، یکی موقع خروج (لاگ آوت دستی)، یکی بصورت دستی با انتخاب خود کاربر، یکی موقع تغییر یا ریست پسورد.
تمام اینها قابل فعال و غیرفعال کردن است و ضمنا بعضیاش چند حالت کانفیگ داره و برای کاربران عادی و ادمین هم تنظیم جدا وجود داره! یعنی آخر انعطاف که البته به قیمت افزایش حجم و پیچیدگی سیستم هم هست! ولی بهرحال ما میخوایم یه سیستم لاگین فوق حرفه ای و منعطف رو درست کنیم. غیر از اینه؟
حالا بخوام توضیح تمام موارد کانفیگ این متغییرها رو بدم از حوصله خارجه، بنابراین فقط یکی دو نکته رو میگم.
اون قضیه تغییر کلید لاگین بصورت دستی توسط خود کاربر چیه؟ خب مال وقتی هست که مثلا کاربر روی سیستم جای دیگری لاگین کرده و بعد یادش رفته لاگ آوت کنه و حالا یادش افتاده و میخواد مطمئن بشه از اینکه دسترسی اون سیستم به اکانتش قطع میشه. پس درخواست تغییر کلید لاگین رو میده و سیستم یک کلید لاگین جدید تولید و با کلید لاگین قدیمی در رکورد اکانت کاربر جایگزین میکنه. یک کاربرد دیگر این گزینه میتونه در مواقعی باشه که کاربر حس میکنه کسی بصورتی به اکانتش نفوذ کرده و مثلا یک هکری چیزی در کاره، که میتونه از این گزینه برای قطع دسترسی فوری هکر استفاده کنه؛ البته احتمالا بعدش باید دنبال راه اصلی نفوذ هکر هم گشت که این قضیه تکرار نشه!
البته اینو بگم که اگر تنظیمات سیستم در حالتی باشن که در اوقات دیگر، مثل موقع لاگین، لاگ آوت، یا در هر درخواست، کلید لاگین بصورت خودکار عوض میشه، بطور خودکار در اون مواقع چه کاربر بخواد و چه نخواد مشابه چنین کاری صورت میگیره. علی الخصوص وقتی تنظیم تغییر خودکار کلید لاگین در هر درخواست روشنه، اصولا نیازی به این گزینه نیست چون با هر درخواست این عملیات داره انجام میشه، و به همین خاطر وقتی تغییر خودکار کلید لاگین در هر درخواست فعال باشه این گزینهء تغییر دستی کلید لاگین از گزینه ای نمایش داده شده برای کاربر حذف میشه و در دسترس نیست. البته بنده این امکان که کاربران بتونن بطور دستی کلید لاگین خودشون رو تغییر بدن هم بصورت قابل تنظیم گذاشتم که اگر صلاح دیدیم فعال یا غیرفعالش کنیم، چون فکر کردم ممکنه توسط همین گزینه سوء استفاده ها و مشکلات پیشبینی نشده ای پیش بیاد. ولی ادمین در هر صورت همیشه این گزینه رو در اختیار داره (مگر اینکه گفتم گزینهء تغییر خودکار کلید لاگین در هر درخواست برای اکانت ادمین فعال باشه).

eshpilen
یک شنبه 11 آبان 1393, 23:45 عصر
توضیح بیشتر
میدونی آپشن http only موقع ست کردن کوکی چیه و چرا استفاده میشه؟


برنامت چی بوده؟
همون سیستم رجیستر و لاگین بنده دیگه!


کدها و فایلات یکم زیادو شلوغه کل ماجرا و ارتباطارو سخت میشه فهمید.
از سخت هم سخت تره واسه دیگران :لبخند:


تا اونجایی که من فهمیدم چارچوب اصلی همون مواردی هست که گفتم توو پست اول و بقیه آپشنا واسه محکم کردم کده.
اونا که گفتی خیلی کلی بود. فقط یه بخش و یکسری موارد مشخص که گرچه مهم بودن ولی از نظر امنیتی بقیهء چیزا رو نمیشه گفت اهمیت کمتری دارن یا لازم نیستن. خیلی سخته این کار و اینطور گزینش کردن. وقتی شما میای از الگوریتم هش خفن استفاده میکنی بقیه چیزا هم مهم میشن. بارها گفتم امنیت مثل یک زنجیره که استحکامش برابر استحکام ضعیف ترین حلقهء اونه.
متاسفانه امنیت همه چیزش درهم تنیده است. نمیشه به این راحتی چیزی رو جدا کرد و گفت اهمیتش کمه یا آپشناله. فقط میتونی سعی کنی تاحدی که میتونی همه چیز لازم رو تا سطح خوبی درست کنی، و اگر وقت نداشتی میای خب اونا رو که ظاهرا مهمتر یا پایه تر هستن انجام میدی، ولی انوقت هیچوقت نمیتونی مطمئن باشی و ادعا کنی که امنیت برنامت بالاست. از همون چیز ظاهرا کوچک و ساده و کم اهمیت میبینی یوقت نفوذ صورت میگیره یا همون نکتهء کوچک جلوی یک نفوذ یا شدت خسارت رو میگیره. بارها این مسائل بوده. مشکل در بحث امنیت همینه که شما باید تمام روزنه ها رو تاحداکثر ممکن ببندی، و حتی یک مورد هم باقی نمونه، ولی هکرها فقط کافیه یک مورد غفلت و ضعف گیر بیارن و از همونجا نفوذ کنن و این همه زحمت و بقیهء امنیت سیستم بیهوده بشه.
البته من دارم در یک سطحی از امنیت حرفه ای و در سطح آکادمیکش صحبت میکنم چون عنوان و هدف شما در ظاهر هم که شده اینطور تعریف شده، وگرنه برای افراد عادی و برنامه های عادی که این حرفا نیست. حالا شما اگر نمیخوای و سردرگم شدی از این همه مطلب و جزییات و پیچیدگی میتونی بگی تا دیگه ادامه ندم به این شکل، ولی بنده دیگه پروژهء شما رو قابل درجه بندی امنیتی نمیدونم چون واقعا معیار روشن و مطمئنی نداره و کار بسیار دشواریه؛ البته شاید تاحدودی نسبت به سیستمهای دیگر کم و بیش در سطح خودش بشه مقایسه کرد.


یه نکته ی دیگه , من یه جا دیدم سرور کلاستر با 25 gpu توو بروت فورس هر ثانیه 180 بیلیون پسورد md5 چک میکنه.
حالا اگه salt هم داشته باشه پسورد و اگه 8 کاراکتری باشه 10 ساعت زمان میبره.
همی پسورد هشتاییرو اگه با salt رندوم و تووی حلقه ی 1000 تایی بزاریم 124 روز.
هش pbkdf2 با الگوریتم sha512 و 1000 دور و 8 کاراکتر 700 سال.
bcrypt هم 3000 سال.
خوب اینجوری اگه یه پسورد امن طولانی تر و salt ای هم به اندازه ی طول پسورد در نظر بگیریم -md5- با دور 5000 تا خوب دیگه تا حد زیادی امنیت برقراره حالا واسه محکم کاری pbkdf2 اینطور نیست؟ یا قضیه پیچیده تره؟:لبخند:
چیزایی که میگی تاحدی کلی و مبهم میبینم.
در واقعیت باید دقیقتر صحبت کرد و پارامترهای بیشتری در کار هست.
ما سعی میکنیم امنیت رو تاحدی که میتونیم بالا ببریم، اینطوری دیگه خیالمون راحتتره و وابسته به حدس و تصور و پارامترهای کمتری هستیم. وقتی bcrypt هست چرا pbkdf2؟
پسورد طولانی هم که مجبور کنیم کاربران انتخاب کنن لزوما به معنای پسورد قوی نیست. حتی اگر چکهای دیگر هم توش بذاری مثلا بگی حتما یک عدد، یک حرف بزرگ، یک حرف کوچک، یک علامت خاص هم توش باشه. معمولا کاربران سعی میکنن بهرحال این سیستم رو از هر راهی که میتونن دور بزنن (مثلا من خودم خیلی جاها از پسوردهایی مثل Aa123456@ در سیستمهای سختگیر استفاده کردم) و خوشون حتی اگر بخوان هم پسوردهایی خیلی ضعیف تر از آنچه که یک پسورد کاملا رندوم است انتخاب میکنن. فردا یک هکر زیرک اومد یه برنامه هوشمند و دیکشنری مخصوص برای تست همین موارد و الگوها درست کرد، اونوقت امنیت پایین تر میاد. اصلا قابل پیشبینی نیست و کسی که انگیزه و وقت و سوادش رو داشته باشه یوقت میبینی کاری میکنه و چیزی درست میکنه و بیرون هم شاید منتشر کنه که ما فکرش رو هم نمیکردیم. بخاطر همین باید سعی کرد بالاترین امنیت ممکن درصورت بروز هر رخداد غیرمنتظره ای رو بدست آورد تاحدی که صرف میکنه البته و برای زمان حال خودش هزینه و مشکلات بیش از حد ایجاد نمیکنه. فکر نمیکنم استفاده از bcrypt هم هزینه و مشکل خاصی داشته باشه و پارامتر تعداد دورش هم قابل تنظیمه اگر فکر میکنید زیادی سنگینه میتونید کمترش کنید.
من توی سیستم خودم اصلا سیستم تعیین الگوی پسورد و نمیدونم درجه بندی و اینا نذاشتم چون بنظرم زیاد مهم و اساسی نبود و در عمل راحت میشه اینا رو گول/دور زد و خیلی ها همین کار رو میکنن. مثلا یه پسوردی مثل Aa123456@ رو توی این سیستمها وارد کنی درجه میره تا آخر میره روی سبز میگه امنیت درحد عالی و خفن پفن! ولی آیا واقعا اینطوره؟

***BiDaK***
دوشنبه 12 آبان 1393, 00:14 صبح
میدونی آپشن http only موقع ست کردن کوکی چیه و چرا استفاده میشه؟

کوکی نمیتونه از سمت کلاینت در دسترس قرار بگیره.
منظورم این تیکه بود:


البته من یک کوکی دیگر هم دارم که سمت سرور کنترل و حذف میشه

مگه چنتا کوکی استفاده میکنی؟
من اینجوری فک میکنم. یکی یوزر آیدی و یک کوکی که در دیتابیس ذخیره میکنم واسه autologin.



احراز هویت هم در برنامه بنده با سشن انجام نمیشه (با کوکی و دیتابیس کار میکنه)

از همون کوکی auto login هم میشه استفاده کنیم یا یکی جدا؟
از سشن چه استفاده هایی کردی؟
فایل های کانفیگت جدا جداس.دلیل خاصی داشتی؟


این سیستمو بگمونم بشه پیادش کرد http://www.freesmile.ir/smiles/305320_JC_thinking.gif

***BiDaK***
دوشنبه 12 آبان 1393, 00:26 صبح
مثلا الان در سایت برنامه نویس وقتی لاگین میکنید فردا هم دوباره کامپیوتر رو روشن میکنید میاید توی سایت هنوزم لاگین هستید چطوری؟
منم در برنامم از کوکی محتوی کلید برای این کار استفاده کردم. این کلید یک رشتهء رندوم طولانی است که از همون موقع ثبت نام برای هر کاربر تولید و در رکورد اکانتش درج میشه. ولی درواقع این کلید میتونه به ازای هر بار لاگین دستی کاربر یا حتی هر درخواست، و یکسری عملیات دیگر، عوض بشه، که این برای امنیت خوبه، ولی عیبش اینه که مثلا اگر کاربر قبلا روی PC1 لاگین بوده حالا میاد روی PC2 لاگین میکنه، کلید لاگین عوض میشه و بنابراین PC1 از لاگین خودکار خارج میشه. مگر اینکه ما بیایم و یجوری یه فکری بکنیم که کاربر بتونه همزمان روی چند سیستم لاگین باشه، ولی بنده بخاطر پیچیدگی افزوده و هزینه ای که این کار داشت از این مورد صرفنظر کردم و گفتم فقط این گزینهء تغییر کلید لاگین رو بصورت قابل کانفیگ کامل میذارم، چون از طرفی فکر میکنم هر حالت دیگری بهرحال امنیت رو مقداری پایین میاره.

خوب یک کوکی old بایک شناسه ای مربوط به سیستم هم در نظر گرفته بشه.
مثلا استفاده از php_uname() و ....

eshpilen
دوشنبه 12 آبان 1393, 00:55 صبح
مگه چنتا کوکی استفاده میکنی؟
من اینجوری فک میکنم. یکی یوزر آیدی و یک کوکی که در دیتابیس ذخیره میکنم واسه autologin.
اول یکی استفاده میکردم ولی بعدا که خواستم بتونم در سمت کلاینت کوکی لاگین رو پاک کنم یکی دیگه هم اضافه کردم که http only نباشه و بشه با جاوااسکریپت در سمت کلاینت بهش دسترسی داشت. ولی اگر فقط همون یدونه کوکی رو میذاشتم از نظر امنیتی درست نبود چون کوکی هایی که http only نباشن دربرابر حمله های XSS ضعف دارن. البته ناگفته نماند که رمز موجود در این دو کوکی با هم یکسان نیست چون اگر باشه اونوقت فرقی نمیکنه و هکری که بتونه رمز موجود در یک کوکی رو بخونه رمز کوکی دیگر رو داره و بهرحال میتونه به سیستم نفوذ کنه.


از همون کوکی auto login هم میشه استفاده کنیم یا یکی جدا؟
هان؟ :متفکر:


از سشن چه استفاده هایی کردی؟
یعنی چی چه سشن هایی؟!
من توی سشن فقط موارد معدود و کم اهمیتی مثل هش کد کپچا رو ذخیره میکنم. سشن بیشتر به درد ذخیره همین اطلاعات موقتی میخوره و چون از نظر امنیتی هم همینطوریش زیاد جالب نیست نخواستم توش اطلاعات حساس تری بذارم.


فایل های کانفیگت جدا جداس.دلیل خاصی داشتی؟
خب معلومه بهتره هرچی دسته بندی تر باشه و حجم هرکدام کمتر بشه خواناتره و بهتر میشه مدیریت و استفاده کرد!
بر اساس نوع کاربرد و مقوله، متغییرهای کانفیگ مشابه رو هرکدام توی فایل کانفیگ جداگانه با اسم مناسب گذاشتم.


خوب یک کوکی old بایک شناسه ای هم در نظر گرفته بشه.
خب اینجوری باید یک کلید دیگر هم در دیتابیس ذخیره کنیم. بعد حالا بنظر شما اگر بجای دوتا PC سه تا بود چی؟ یکی دیگه باز اضافه کنیم؟ چهارتا چی؟ پنج تا چی؟ ... شاید یکی روی گوشی و تبلت هم بخواد لاگین بمونه!
بعدم یک مسئله ای هست اینکه اصلا کلید لاگین رو برای چی تغییر میده سیستم مگه بخاطر امنیت نیست و اینکه اگر یک کلید نشت کرد سرقت شد و خلاصه در دسترس نفوذگر قرار گرفت بهرصورتی، از درجهء اعتبار ساقط بشه و عمرش کوتاه باشه، و اگر قرار باشه یدونه قدیمی رو هم برای مدت طولانی نگه داریم و معتبر باشه خب به این هدف تاحد قابل توجهی خدشه وارد نمیشه؟
البته بحث بازم از این پیچیده تره و جزییات بیشتری داره. ضمنا بنده روشهایی رو در نت دیدم طراحی کرده بودن برای این موضوع که بنظرم از اینکه شما گفته خیلی پیشرفته تر بود و شاید از نظر امنیتی هم بهتر بوده ولی جزییاتش یادم نیست و مطمئن نیستم.
بهرحال بنده این امکان رو خیلی مهم و ضروری ندونستم که لاگین ماندن همزمان روی چند سیستم ممکن باشه و از این کار اضافه و پیچیدگی افزوده و ریسک امنیتی اجتناب کردم. تازه در سیستم بنده هم میشه تغییر خودکار کلید لاگین رو خاموش کرد و اینطوری میشه از روی هر تعداد سیستمی همزمان لاگین ماند، ولی خب اونوقت دیگه مزیت امنیتی تغییر کلید لاگین رو نداریم، ولی بهرحال اگر کسی خیلی نیاز داشت میتونه خاموشش کنه و از این قضیه استفاده کنه و بودن این آپشن بنظرم از نبودنش بهتره بالاخره. یه انعطاف افزوده سیستم بنده هم در این زمینه اینه که تنظیم اکانت ادمین و کاربران عادی در این زمینه جداست و لازم نیست لزوما یک سیاست و یک ریسک رو برای تمام هردوی کاربران معمولی و ادمین داشته باشیم. مثلا برای ادمین میتونیم تعیین کنیم که حتی در هر درخواست کلید لاگین عوض بشه (برای حداکثر امنیت)، ولی کاربران عادی اصلا عوض نشه یا فقط تحت لاگین دستی و/یا لاگ آوت و/یا درخواست صریح خودشون عوض بشه.

eshpilen
دوشنبه 12 آبان 1393, 01:01 صبح
خوب یک کوکی old بایک شناسه ای مربوط به سیستم هم در نظر گرفته بشه.
مثلا استفاده از php_uname() و ....
همیشه یادتون باشه اینطور توابع مشخصات سرور رو درمیارن، نه مال کلاینت رو. درمورد کلاینت شما بطور معمول فقط به IP و user agent و اینها دسترسی دارید، نه مشخصات شخصی تر و حساس تر کامپیوترشون.
البته بحث وابسته کردن لاگین به IP هم هست که اونم در سیستم بنده آپشن منعطفی براش وجود داره و هنوز بهش نرسیدیم! ولی بهرحال حتی با وابسته کردن لاگین به IP هم باز اون بحث تغییر کلید لاگین برای امنیت فایده داره (هرچند احتمالا اهمیتش کمتر میشه) چون IP کلاینت اصلی و کسان دیگری میتونه به دلایل مختلف در زمانهای مختلف یکسان یا مشترک باشه. وابسته کردن به user agent هم که زیاد اهمیت نداره چون براحتی قابل جعله و هکری که کلید لاگین کاربر رو بدست بیاره میتونسته user agent اش رو هم بدست بیاره.

***BiDaK***
دوشنبه 12 آبان 1393, 01:05 صبح
همیشه یادتون باشه اینطور توابع مشخصات سرور رو درمیارن، نه مال کلاینت رو.
درسته.حواسم نبود.بعد که دیدمش گرفتم موضوعو

eshpilen
دوشنبه 12 آبان 1393, 19:02 عصر
خب یه چیز دیگه داریم که وابسته کردن لاگین به IP است. یعنی موقعی که لاگین میکنی و کوکی autologin ست میشه مقدار این کوکی به IP ای که ازش لاگین کردی وابسته میشه. البته برای این کار میشه مثلا IP طرف رو در یک فیلد در دیتابیس هم ذخیره کرد و هر بار که میخواید مقدار کلید لاگین موجود در کوکی رو با مقدارش در رکورد اکانت چک کنیم بیایم و برابری IP ها رو هم چک کنیم، ولی من فکر کردم بهتره این کار رو نکنم و هم این اطلاعات اضافه رو به دیتابیس افزوده نکنم و هم اینکه از نظر امنیتی و Privacy ذخیرهء IP کاربر توی دیتابیس میتونه خودش یک امتیاز منفی محسوب بشه. خب من چطور کوکی رو به IP وابسته کردم؟ خب نسبتا ساده است! این بخشی از کد بنده برای مقایسهء مقدار موجود در کوکی کاربر با مقدار موجود در دیتابیس رو ببینید:

if(hash('sha256', $tmp54['autologin_key'].$_SERVER['REMOTE_ADDR'])==$autologin_key)
نکته: دست راست مقدار کلید موجود در کوکی است.
همونطور که مشاهده میفرمایید، ما ابتدا مقدار IP رو به کلید لاگین میچسبونیم، با sha256 هش میکنیم، بعد در کوکی بعنوان کلید لاگین ذخیره میکنیم. در سمت هم سرور برای مقایسه دوباره همین کار رو انجام میدیم و با مقدار موجود در کوکی مقایسه میکنیم.
نکته اینکه خوشبختانه مقدار موجود در ‎$_SERVER['REMOTE_ADDR']‎ توسط هکرها میشه گفت قابل جعل نیست. البته این به این معنا نیست که هکر هیچوقت نمیتونه IP قربانی رو داشته باشه! چرا خیلی وقتا هکر ممکنه همون IP رو واقعا در دسترس داشته باشه، مثلا در یک شبکه داخل یک سازمان یا دانشگاهی یا هرجا که از اتصال اینترنت مشترکی استفاده میکنن، یا درصورت استفاده از پراکسی مشترک، یا ممکنه مثلا در شبکهء تلفن همراه از IP مشترکی برای تعداد کم یا زیادی از کاربران استفاده بشه (این امر در سطح جهان حتی برای سرویسهایی مثل ADSL یا دایالاپ هم میتونه دیده بشه)، IP موقتی بوده و بعد به یک کس دیگری اختصاص پیدا کرده، و خلاصه دلایل و شرایط مختلف. البته باید بگیم در کل بهرحال این روش امنیت رو به میزان چشمگیری بالا میبره. ولی از اون طرف دردسرهای خودش رو هم داره و مثلا اگر IP کاربر به علل مختلفی که ممکن هست و آنچنان غیرمتداول هم نیست عوض بشه از لاگین خارج میشه، از پراکسی جدیدی نمیتونه استفاده کنه، و غیره. بنابراین نباید این ویژگی رو در برناممون بصورت ثابت و نامنعطف بذاریم. کانفیگ برنامهء بنده در این مورد انعطاف کاملی داره و میشه این گزینه رو فقط برای ادمین، فقط برای کاربران عادی، یا برای هر دو فعال کرد، و حتی میشه اون رو بصورت یک آپشن قابل انتخاب در زمان لاگین در اختیار کاربر گذاشت که هرکس هر زمان که خودش خواست بتونه لاگین خودش رو به IP وابسته کنه.

ضمنا اینو اضافه کنم که برای گرفتن IP فقط از همون ‎$_SERVER['REMOTE_ADDR']‎ استفاده کنید ولاغیر، چون IP موجود در یکسری متغییرهای دیگر (مثلا $_SERVER['HTTP_CLIENT_IP'] و یا $_SERVER['HTTP_X_FORWARDED_FOR']) از هدرهای HTTP ست شده در درخواست کلاینت گرفته میشن و بنابراین قابل جعل هستن!

خوب بید؟ :لبخند:

eshpilen
سه شنبه 13 آبان 1393, 13:55 عصر
یک ویژگی امنیتی دیگه که بنده به فکرم رسید و در پروژم پیاده کردن این بود که برای به یاد ماند لاگین هایی که تا باز بودن مرورگر اعتبار دارن هم امکان تعیین محدودیت زمانی گذاشتم.
در خیلی سیستمهای دیگه شما میبینید که تا وقتی مرورگر بسته نشه لاگین کاربر برقراره، ولی این اگر بخواد از نظر امنیتی نامحدود باشه خودش میتونه امنیت رو پایین بیاره. فرضا هکری که کوکی لاگین کاربر رو سرقت کنه میتونه ازش بصورت نامحدود برای دسترسی غیرمجاز استفاده کنه چون تا زمانی که اون کوکی رو به سرور بفرسته کوکی معتبر شناخته میشه، مگر اینکه مثلا سیستم کلید لاگین رو تغییر داده باشه (که این میتونه بعلت غیرفعال بودن این سیستم یا عدم فعالیت مجدد کاربر در سایت صورت نگرفته باشه). یا فرض کنید که کاربر بدون اینکه مرورگر خودش رو ببنده سیستم رو Hibernate کرده و بعد از 24 ساعت که سیستم روشن میشه هنوز مرورگر بازه و کوکی لاگین هم سرجاشه!
فکر میکنم همه موافق باشیم که هدف از لاگین بودن تا زمان باز بودن مرورگر بطور معمول این نیست که دوام لاگین بدون محدودیت باشه، بلکه تازه بعکس در خیلی مواقع بخاطر امنیت هست که میخوایم با بسته شدن مرورگر کاربر از لاگین خارج بشه. بنابراین ما باید بتونیم طول عمر این کوکی ها رو از نظر زمانی هم محدود کنیم و فقط به شرط بسته شدن مرورگر نباشه.
بنده برای این منظور یک متغییر کانفیگ در برنامم گذاشتم که این امکان رو اگر بخوایم میده (پیش فرض عمر این کوکی ها رو روی 12 ساعت گذاشتم که فکر کنم زمان مناسبی باشه). ولی گزینه غیرفعال کردن هم داره که اگر به هر دلیلی کسی خواست بتونه همون رفتار کلاسیک رو داشته باشه.
ضمنا طول عمر/زمان انقضای این کوکی ها رو طبیعتا باید در سمت سرور ذخیره و در هر درخواست چک کنید، چون ست کردن طول عمر کوکی در سمت کلاینت امنیت نداره و قابل دور زدن توسط کلاینت/هکر است و ضمنا با بسته شدن مرورگر هم کوکی باید از بین بره. البته این روش ذخیره و چک کردن زمان انقضا در سمت سرور رو باید درمورد تمام کوکی های دیگر هم که طول عمر اونا با مسئلهء امنیت ارتباط داره انجام داد و فقط محدود به این نوع کوکی نمیشه.

eshpilen
پنج شنبه 15 آبان 1393, 22:15 عصر
یادمه چند سال پیش به مدت مد و محبوب شده بود و این ویژگی تازه اومده بود که صفحهء لاگین بعضی سایتها بجای یک چک باکس ساده remember me (مرا به یاد بسپار) چند گزینهء بیادسپاری داشتن با زمانهای مختلف که کاربر میتونست موقع لاگین انتخاب کنه. هنوزم بعضی سایتها این ویژگی رو دارن ولی نمیدونم چرا دیگه کسی چندان توجهی بهش نمیکنه و این ویژگی فراگیر نشد! البته طبیعتا این گزینه حجم و پیچیدگی کد رو زیاد میکنه، ولی من خودم از دیدگاه امنیتی و تجربه های کاربری خودم به این نتیجه رسیدم که درست و واقعا مفیده. بخاطر همین این رو در برنامه خودم گذاشتم.
توی پروژهء بنده در فایل کانفیگ config_identify.php اگر نگاه کنید چنین کدهایی میبینید:

$autologin_ages=array(

0,
5*60,
20*60,
60*60,
8*60*60,
24*60*60,
3*24*60*60,
7*24*60*60,
30*24*60*60,
3*30*24*60*60,
365*24*60*60,

);
این مربوط به همین قضیه میشه و اون عناصر آرایه زمانها به ثانیه هستن که گزینه های زمان بخاطرسپاری ای رو که کاربر موقع لاگین میتونه انتخاب کنه مشخص میکن. این زمانها در فرم لاگین بصورت خودکار به عبارت های عادی مثل «5 دقیقه» تبدیل و در منوی مربوطه نمایش داده میشن.
ضمنا بنده برای این کانفیگ هم تنظیمات جداگانه برای ادمین و کاربران عادی گذاشتم که باز آخر انعطاف رو داره. چند خط پایین ترش رو نگاه کنید یک متغییر دیگه هست بنام admin_autologin_ages که حاوی همین تنظیمات برای اکانت ادمین است.

نکتهء امنیتی که این امکان داره اینه که زمانهای لاگین رو باید در سمت سرور (هم) چک کنید تا امکان دور زدنش برای کاربر یا هکرها نباشه. بطور مثال وقتی کاربر مشخص کرده که زمان لاگین 20 دقیقه باشه، درسته که بعد از 20 دقیقه کوکی لاگین از مرورگر کاربر پاک میشه (البته اگر مشکلات فنی خاصی در این امر پیش نیان) ولی اگر قبلش یک هکر اون کوکی رو سرقت کرده باشه میتونه ازش سوء استفاده کنه، مگر اینکه زمان انقضای لاگین خودکار در سمت سرور هم ذخیره شده باشه و چک بشه. البته قبلا هم اشاره کرده بودم که بطور کلی زمان انقضای تمام کوکی هایی که زمان اونا از نظر امنیتی اهمیت داره باید سمت سرور هم چک بشه.

خلاصه بنظر من این ویژگی خوبی هست که باید در یه برنامهء کامل و با امنیت بالا وجود داشته باشه. مثلا یوقت من میرم یجا موقتا کار دارم لاگین میکنم و میدونم کارم ده پانزده دقیقه بیشتر طول نمیکشه خب زمان لاگین خودکار رو میذارم روی 20 دقیقه که حتی اگر یادم رفت لاگ آوت کنم یا به هر دلیل دیگری موفق به انجام این کار نشدم، سیستم بصورت خودکار و به موقع از لاگین خارج میشه، و چون میدونم که این مسئله در سمت سرور چک میشه بنابراین هیچ نگرانی ای از بابت مشکلات فنی و حمله های سمت کلاینت ندارم. البته همونطور که بعنوان اولین مقدار در متغییر کانفیگ بند هم مشاهده میکنید، مقدار صفر هم وجود داره که به معنای لاگین ماندن تا زمان باز بودن مرورگر است.

eshpilen
دوشنبه 19 آبان 1393, 21:43 عصر
یه نگاهی به فایل config_password_change_or_reset.php بندازیم متغییرهای کانفیگی درش هست که مربوط به تغییر یا ریست پسورد میشن.

متغییر max_password_reset_emails میگه اگر کسی درخواست ریست کردن پسوردش رو کرد حداکثر چند ایمیل به ایمیل مورد نظر ارسال بشه (طبیعتا در بازهء زمانی ای که توسط password_reset_period مشخص شده).
اینطور محدودیت ها رو خیلی از سیستمها ندارن، ولی بنظر من باید داشته باشن. اگر محدودیت نداشته باشن هرکسی میتونه از این سیستمها برای آزار و اذیت و سوء استفاده بهره برداری کنه. مثلا من میدونم ایمیل شما که باهاش به احتمال زیاد در این سایت ثبت نام کردید چیه، میام درخواست ریست پسورد شما رو میدم و یک اسکریپت ساده مینویسم که این درخواست رو بطور خودکار به تعداد زیاد تکرار کنه، در نتیجه در زمان کوتاهی میشه صدها و هزاران ایمیل از طرف این سایت به آدرس ایمیل شما فرستاد! آیا این چیز بدون مشکلیه بنظر شما؟ ضمنا این قضیه رو بنده قبلا روی همین سایت برنامه نویس تست کردم و 100% جواب میده، اونم فقط با یک فایل HTML ساده و مقداری جاوااسکریپت روی لوکال!
البته من برای تمام اینطور متغییرها اکثرا مقدارهای خاصی رو هم قرار دادم که با اونا میشه تعداد رو نامحدود هم کرد. مثلا اگر مقدار max_password_reset_emails رو برابر ‎-1 قرار بدید، تعداد ایمیل های ارسالی نامحدود میشه.


متغییر بعدی password_reset_period است که فاصلهء زمانی ای رو که در اون لینک ریست پسورد معتبر است مشخص میکنه.

متغییر بعدی change_autologin_key_upon_new_password.
این متغییر مشخص میکنه که هنگامی که پسورد جدیدی توسط کاربر تعیین شد (در نتیجهء تغییر پسورد یا ریست پسورد)، آیا کلید autologin هم عوض بشه یا نه. مقدار پیشفرض رو روی true گذاشتم چون فکر میکنم از نظر امنیتی تقریبا شکی نیست که در اینطور موارد باید کلید لاگین رو هم تغییر داد. فرض کنید مثلا کاربر شک داره که کسی به اکانتش دسترسی پیدا کرده، میاد و پسوردش رو تغییر میده، ولی اگر کلید لاگین تغییر نکنه ممکنه هکر یا فرد غیرمجازی که قبلا لاگین کرده همونطور لاگین بمونه. البته طبیعتا امکان غیرفعال کردن این گزینه هم هست چون سیستم ما باید انعطاف کاملی در پیکربندی و سناریوهای پیشبینی شده و نشده داشته باشه.

متغییر admin_change_autologin_key_upon_new_password هم مثل همون قبلیه منتهی این تنظیم برای اکانت ادمین است (قبلی برای کاربران عادی بود). اینجا هم باز ما انعطاف رو با گذاشتن تنظیمات جداگانه برای ادمین و کاربران معمولی به اوج میرسونیم! دیگه چه نیاز و سناریویی هست که برنامهء ما نتونه پوشش بده؟ ما میتونیم تنظیمات و سطح احتیاط/امنیت مختلفی رو برای کاربران معمولی و ادمین تعیین کنیم؛ مثلا ممکنه برای کاربران عادی بخوایم یک مقدار از سختگیری در امنیت رو فدای یوزرفرندلی بیشتر بکنیم، ولی برای اکانت ادمین که مهمتر و حساس تره این کار رو نکنیم.

ضمنا یه نکته ای هم که در مورد ریست کردن پسورد بنظرم میرسه اینه که، کاربر میاد و درخواست ریست کردن پسورد رو میده (با وارد کردن ایمیلش)، شما یک لینک حاوی توکن رندوم رو تولید میکنید و به ایمیل کاربر ارسال میکنید، این لینک مثلا تا 24 ساعت اعتبار داره، کاربر میاد و قبل از تموم شدن این 24 ساعت درخواست ارسال مجدد ایمیل رو میکنه (شاید ایمیل قبلی به هر علتی به دستش نرسیده)، شما میاید و یک توکن و لینک جدید تولید میکنید و به ایمیلش ارسال میکنید؟ من میگم خیر، شما باید از همون توکن قبلی استفاده کنید و توکن جدیدی تولید نکنید، چون اگر توکن رندوم رو مجددا تولید کنید توکن قبلی بی اعتبار میشه و این میتونه مشکلات کاربری ایجاد کنه (کاربر چندتا ایمیل محتوی چند لینک خواهد داشت که فقط یکی از اونا معتبره و این در مواردی میتونه کاربر رو سردرگم و دچار مشکل کنه). البته بعد از اینکه 24 گذشت توکن بی اعتبار میشه و باید توکن جدیدی تولید کرد.
البته این نکته بیشتر از نظر یوزرفرندلی بود و به امنیت ارتباط چندانی نداره.

eshpilen
دوشنبه 19 آبان 1393, 21:54 عصر
در جریان پروژهء سیستم رجیستر و لاگین، بنده با خیلی کانفیگ های امنیتی مختلف برخورد کردم که نمیدونستم دقیقا باید چه تنظیمی برای اونا بذارم. اگر میخواستم روی دونه دونه اونا تحقیق کنم و به جواب روشنی برسم، وقت و انرژی خیلی زیادی تلف میشد و تازه بازم امکان اینکه نیازها و شرایط دیگری وجود داشته باشن که این پیشبینی ها و تصمیم ها بهش اعمال نشن زیاد بود. بخاطر همین بنده به این نتیجه رسیدم که باید هر مکانیزمی که در برنامه میذارم از نظر امکان کانفیگ حداکثر انعطاف ممکن رو داشته باشه تا هرکس در هر شرایط و نیازی بتونه برنامه رو براحتی تطبیق بده.
ممکنه امکان یک تنظیمی که بنده گذاشتم در عمل اصلا هیچوقت نیاز نباشه یا حتی از نظر امنیتی درست نباشه، ولی من امکان تنظیمش رو گذاشتم چون بهرحال ضرر خاصی نداشت و از اینکه یک وقت به احتمال کم هم نیاز میشد ولی در برنامه امکانش نبود خیلی بهتره.
بنده هیچ سیستمی رو تاحالا ندیدم که تا این حد جزییات رو درنظر گرفته باشه و تا این حد قابل تنظیم در تمامی جزییات باشه. و البته این همه امکان تنظیم و توجه به جزییات، مسلما حجم و پیچیدگی کدنویسی رو هم زیاد میکنه، ولی من برای هدف طراحی یک سیستم بی نقص چارهء دیگری ندیدم!
تازه باوجود تمام اینها، بنده هنوز برنامم رو از نظر امکانات پایه کامل نمیدونم و بنظرم میشه چند امکان دیگر و انعطاف و تنظیمات بیشتری رو هم بهش اضافه کرد.

eshpilen
شنبه 24 آبان 1393, 22:30 عصر
اخیرا عده ای از منافقین کوردل به سیستم رجیستر و لاگین بنده توهین کردن!
اما چه کسی میتواند خورشید را با پارچه ای بپوشاند؟
الان چنتا ویژگی خفن دیگه از سیستم رجیستر و لاگین خودم رو میگم تا مشت محکمی به دهان استکبار جهانی زده باشم :لبخند:
به افتخار سیستم رجیستر و لاگین اتمی (انرژی هسته ای حق مسلم ماست :تشویق:)

خب یه سیستم دیگه که من توی برنامم گذاشتم سیستم پر کردن خودکار پسورد بود. حالا این سیستم چیه؟ البته اینم بگم که این سیستم ضروری نیست و به امنیت ربطی نداره ولی برای یوزرفرندلی خوبه.
خب شما شاید در بعضی سایتها دیده باشید که مثلا موقع رجیستر کردن فرم رو سابمیت میکنید و بعد بخاطر یک خطایی کمبودی چیزی از طرف سرور برمیگرده بعد میبینید که توی فیلد پسورد یه چیزی پر شده ولی قیافش عجیب و غریبه (مثلا طولش معمولا زیاده و با پسوردی که شما وارد کرده بودید یکی نیست). توی سورس هم میرید مشاهده میکنید که یکسری کاراکترهای رندوم عجیب اونجا هست! خب اون چیه بنظر شما؟ من خودم اغلب این کاراکترها رو پاک میکردم و دوباره پسورد خودم رو وارد میکردم چون فکر میکردم که شاید سیستم اونا یه مشکلی داره و اگر با اون محتوی فیلد پسورد ثبت نام کنم دیگه نمیتونم به اکانت مورد نظر لاگین کنم!! این نشون میده که این امکان برای یوزرفرندلی شاید زیاد هم فایده نداشته باشه :لبخند:
بهرحال من توی برنامم گذاشتم و بازهم بصورت آپشنال البته (بصورت پیشفرض هم روشنه البته).

خب این سیستم تاجاییکه من حدس زدم و فهمیدم اینه که پسورد یک بار که میره به سمت سرور بعد اونجا هش یا رمزی چیزی میشه و دوباره برمیگرده توی فرم بجای پسورد کاربر اون هش یا رمز پر میشه که دیگه نیاز نباشه کاربر مجدد فیلدهای پسورد رو پر بکنه. درست؟

اما چرا باید هش بشه آیا نمیشه اصل پسورد کاربر رو توی فرم پر کرد؟
خب فکر میکنم باید گفت که بخاطر مسائل امنیتی این کار درست نیست. در تمام سیستمهایی هم که این سیستم کذایی رو ندارن شما مشاهده میکنید که یک بار که فرم سابمیت میشه تمام فیلدها بصورت خودکار با مقادیری که قبلا توسط کاربر پر شدن پر میشن الا فیلدهای پسورد!

البته بنظر میاد که در سیستمهای امروزی فایده و اهمیت این مکانیزم کمتر شده چون با روشهای سمت کلاینت و ایجکس و اینها میشه خیلی از موارد خطای فرم رو در سمت کلاینت شناسایی و حل و فصل کرد (مثلا حتی یک چیزهایی مثل کپچا رو میشه بدون سابمیت شدن فرم با ایجکس چک کرد) و کمتر پیش میاد که فرم سابمیت بشه و باز دوباره به همون صورت برگشت بخوره. البته هنوزم این اتفاق کم نمی افته!

حالا نظری چیزی راجع به این سیستم دارید بگید تا بقیش بعدا چون الان دیگه حس و حالش نیست.

bagherok
شنبه 24 آبان 1393, 22:44 عصر
خب آخرش رو بگو
میخوای چیکار بکنی یا کردی!
گوش میدم:چشمک:

eshpilen
شنبه 24 آبان 1393, 22:53 عصر
خب آخرش رو بگو
میخوای چیکار بکنی یا کردی!
گوش میدم:چشمک:
آخر چی رو؟
گفتم که فعلا حس و حالش نیست.
امروز همش پای کامپیوتر بودم.
الان دیگه وقت لالا!

H:Shojaei
شنبه 24 آبان 1393, 22:55 عصر
اما چرا باید هش بشه آیا نمیشه اصل پسورد کاربر رو توی فرم پر کرد؟
خب فکر میکنم باید گفت که بخاطر مسائل امنیتی این کار درست نیست. در تمام سیستمهایی هم که این سیستم کذایی رو ندارن شما مشاهده میکنید که یک بار که فرم سابمیت میشه تمام فیلدها بصورت خودکار با مقادیری که قبلا توسط کاربر پر شدن پر میشن الا فیلدهای پسورد!

البته بنظر میاد که در سیستمهای امروزی فایده و اهمیت این مکانیزم کمتر شده چون با روشهای سمت کلاینت و ایجکس و اینها میشه خیلی از موارد خطای فرم رو در سمت کلاینت شناسایی و حل و فصل کرد (مثلا حتی یک چیزهایی مثل کپچا رو میشه بدون سابمیت شدن فرم با ایجکس چک کرد) و کمتر پیش میاد که فرم سابمیت بشه و باز دوباره به همون صورت برگشت بخوره. البته هنوزم این اتفاق کم نمی افته!

حالا نظری چیزی راجع به این سیستم دارید بگید تا بقیش بعدا چون الان دیگه حس و حالش نیست.
یه سوال...
چرا این که پسورد بره سمت سرور و برگشت بخوره بدون هیچ دخالتی تو هیچ قطعه کدی به جز این که اندازه و مچ بودن هردو فیلد پسورد چک بشه اشکال داره که همونطور قرار بگیره تو فیلدهای پسورد؟؟
مثلا نهایت اتفاقی که میافته چک میشه طولش که کمتر از 8 بود فرم ارسال نشه و همون مقداری که کاربر ارسال کرده نمایش داده بشه...
(البته قبلش واسه نمایش فیلتر و اینا بشه بعد نمایش داده بشه)
سمت کلاینت هم هرچقدر که ولیدیشن گذاشته بشه بازم واسه امنیت بیشتر بهتره سمت سرور هم این ولیدیشن ها گذاشته بشن چون همیشه سمت کلاینت اسمش روشه دیگه سمت کلاینته تا حدودی میشه دورش زد...

bagherok
شنبه 24 آبان 1393, 23:16 عصر
آخر آخرین پستت رو دیگه.
نگو حس و حالش نیست..

یه چیزی که الان به ذهنم رسید اینه اطلاعات درست ذخیره بشن (دیتابیس یا سشن)
اطلاعات ورودی که اشتباه وارد شدند در قالب یه فرم جدید نمایش داده بشه.(ومقادیر درست نمایش داده نشند.)