PDA

View Full Version : سوال: کد امنیتی در فرمها



ساراعلی
سه شنبه 01 اردیبهشت 1394, 22:12 عصر
سلام دوستان من تو زمینه php مبتدی هستم الان تو پروزه ام به مشکلی برخوردم اگه کسی میدونه راهنماییم کنه ممنون میشم

من یک فرم نوشتم و با جاوااسکریپت اعتبار سنجیش کردم و در اخر فرمم کد امنیتی گذاشتم برای جلوگیری از پیامهای هرز و روبات و این چیزا حالا که میخوام فرمم رو submit کنم اگه فیلدها به طور صحیح پر شده باشن رو دکمه submit که کلیک میکنم فرم رو ارسال میکنه با اینکه کد امنیتی اشتباه وارد شده!! و فقط اون پیغام کد امنیتی صحیح نیست رو نشون میده و اطلاعات داخل فیلدها رو پاک میکنه یعنی ارسال میکنه !!! چطوری باید فرم و کد امنیتی رو به هم ارتباط بدم و براش تعریف کنم که تا وقتی که کد امنیتی به طور صحیح وارد نشده اطلاعات فیلد رو ارسال نکنه؟؟؟:متفکر:

-سیّد-
سه شنبه 01 اردیبهشت 1394, 23:36 عصر
سلام

اولاً خوب بود کدتون رو هم می‌ذاشتید تا بشه روش دقیق‌تر صحبت کرد.

ثانیاً این رو خوب به خاطر بسپرید: اعتبارسنجی توسط جاوااسکریپت، به هیچ وجه نمی‌تونه از سوء استفاده از سیستم جلوگیری کنه. اعتبارسنجی وقتی کامل می‌شه که سمت سرور انجام بشه.
اعتبارسنجی سمت client و توسط جاوااسکریپت، فقط سرعت کار رو برای کاربر معمولی (که نمی‌خواد سوء استفاده کنه) بالا می‌بره و اشتباهات احتمالی در ورود اطلاعات رو قبل از ارسال به سرور detect می‌کنه و به کاربر تذکر می‌ده.
بنابراین اعتبارسنجی توسط javascript مفیده، ولی اصلاً کافی نیست.

ثالثاً اگه همچنان می‌خواین توسط جاوااسکریپت جلوی ارسال فرم رو بگیرید، نباید که فیلدها رو پاک کنید! باید فقط فرم رو submit نکنید. برای جلوگیری از submit شدن فرم، می‌تونید توی رویداد onsubmit فرم، return false کنید:


<form action="test.php" onsubmit="return false">
...
<input type="submit" />
</form>

این فرمی که مثال زدم رو هیچ جوری نمی‌تونید submit کنید! حالا اگه می‌خواین کاربردی بشه و در صورت وجود مشکل توی فرم submit نشه، می‌تونید خروجی تابع validate رو return کنید:


<form action="test.php" onsubmit="return validate()">
...
<input type="submit" />
</form>

دقت کنید که این return false باید توی scope رویداد مورد نظر باشه، و اگه تابع validate مقدار false رو برگردونه، ولی حواستون نباشه و return رو جا بندازید و در نتیجه از داخل onsubmit این مقدار رو برنگردونید، فرم همیشه submit می‌شه:


<form action="test.php" onsubmit="validate()">
...
<input type="submit" />
</form>

البته نمی‌دونم این روش چقدر استاندارد هست و همه‌ی مرورگرها ازش پشتیبانی می‌کنن یا نه.

روش دیگه اینه که جلوی event رو بگیرید که نتونه کار خودش (یعنی submit کردن فرم) رو انجام بده:


<form action="test.php" onsubmit="event.preventDefault();">
...
<input type="submit" />
</form>


در نهایت هم این که در صورت اشتباه بودن کد امنیتی، نباید جلوی فرستاده شدن اطلاعات رو بگیرید، بلکه باید اطلاعات فرستاده بشه، بعد سرور بگه که کد امنیتی غلط بود. چرا؟ به همون دلیل که گفتم: این کار باید سمت سرور انجام بشه.
دلیلش اینه که اگه شما توی javascript می‌تونید تشخیص بدید که کد امنیتی درست وارد شده یا غلط، پس اون کاربر نابکار(!) و روبات هم می‌تونن بفهمن مقدار درست کد امنیتی چیه. تنها حالتی که کد امنیتی از دسترس اونها امن می‌مونه، ذخیره‌سازی اون سمت سرور، و چک کردنش همونجا هست. یعنی مثلاً شما یه session درست می‌کنید برای کاربر، یه کد امنیتی هم generate می‌کنید، و مقدار درستش رو توی session قرار می‌دید. بعد که فرم فرستاده شد، چک می‌کنید مقداری که برای شما فرستاده شده با مقدار داخل session یکی هست یا نه.

ساراعلی
چهارشنبه 02 اردیبهشت 1394, 22:52 عصر
مرسی از راهنماییتون ولی من فرمم رو با برنامه dreamweaver طراحی کردم و همونجا هم با امکانات اعتبار سنجی جاوااسکریپت خوده برنامه فرمم رو اعتبار سنجی کردم ,ولی این کد امنیتی رو با php نوشتم و اعتبار سنجی کردم حالا نمیدونم چطوری این دوتا رو به هم ربط بدم



<?php session_start();
if(isset($_POST['Submit'])){ // code for check server side validation if(empty($_SESSION['captcha_code'] ) || strcasecmp($_SESSION['captcha_code'], $_POST['captcha_code']) != 0 ){ $msg= "<span style='color:#f7601d;font-size:14pt;font-family:yekan'>کد امنیتی صحیح نیست</span>";// Captcha verification is incorrect. }else{// Captcha verification is Correct. Final Code Execute here! $msg="<span style='color:green'>The Validation code has been matched.</span>"; }}
?>







<!DOCTYPE html>


<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />


<title>Untitled Document</title>


<script src="SpryAssets/SpryValidationTextField.js" type="text/javascript"></script>
<script src="SpryAssets/SpryValidationTextarea.js" type="text/javascript"></script>
<link href="SpryAssets/SpryValidationTextField.css" rel="stylesheet" type="text/css" />
<link href="SpryAssets/SpryValidationTextarea.css" rel="stylesheet" type="text/css" />
<link href="phpcaptcha/css/style.css" rel="stylesheet" type="text/css" />
<script type='text/javascript'>
function refreshCaptcha(){
var img = document.images['captchaimg'];
img.src = img.src.substring(0,img.src.lastIndexOf("?"))+"?rand="+Math.random()*1000;
}




</script>
</head>


<body>
<form dir="rtl" id="form1" name="form1" method="post" action="">


<table class="momtable" width="682" cellpadding="3" cellspacing="15" dir="rtl">
<tr>
<td width="322">عنوان آگهی:</td>
<td width="301"><span id="sprytextfield1">
<label for="onvan"></label>
<input type="text" name="onvan" id="onvan" maxlength="38 chars"/>
<span class="textfieldRequiredMsg">لطفا عنوان آگهی را وارد کنید.</span></span></td>
</tr>
<tr>
<td>متن آگهی:</td>
<td><span id="sprytextarea1">
<textarea name="txtName2" id="txtName2"></textarea>
<span class="textareaRequiredMsg">لطفا متن آگهی را وارد نمایید.</span><span class="textareaMaxCharsMsg">کاراکترها بیشتر از 500 حرف مجاز نیست.</span><span class="textareaMinCharsMsg">کاراکترهای کمتر از 30 حرف ،مجاز نیست.</span></span></td>
</tr>
<tr>
<td>نام شرکت:</td>
<td><input class="unrequired" type="text" name="txtFamily2" id="txtFamily2" maxlength="38 chars"/></td>
</tr>
<tr>
<td align="right">نام و نام خانوادگی:</td>
<td><input class="unrequired" type="text" name="txtFamily3" id="txtFamily3" maxlength="25 chars"/></td>
</tr>
<tr>
<td>شهر:</td>
<td><input type="text" name="textfield" id="textfield" maxlength="20 chars"/></td>
</tr>
<tr>
<td>آدرس:</td>
<td><label for="address"></label>
<span id="sprytextarea2">
<textarea name="address" id="address"></textarea>
<span class="textareaMaxCharsMsg">Exceeded maximum number of characters.</span></span></td>
</tr>
<tr>
<td>تلفن تماس:</td>
<td><label for="phon"></label>
<label for="phon"></label>
<span id="sprytextfield5">
<input type="text" name="phon" id="phon" />
<span class="textfieldRequiredMsg">لطفا شماره تماس خود
را وارد کنید.</span></span></td>
</tr>
<tr>
<td>موبایل:</td>
<td><span id="sprytextfield3">
<label for="mobile"></label>
<input type="text" name="mobile" id="mobile" />
<span class="textfieldRequiredMsg">لطفا شماره موبایل خود را واردکنید.</span><span class="textfieldInvalidFormatMsg">شماره موبایل صحیح نیست.</span></span></td>
</tr>
<tr>
<td>ایمیل:</td>
<td><span id="sprytextfield2">
<input type="text" name="textfield5" id="textfield5" value=""/>
<span class="textfieldRequiredMsg">لطفا نشانی ایمیل خود
را وارد کنید.</span><span class="textfieldInvalidFormatMsg">نشانی ایمیل نامعتبر است.</span></span></td>
</tr>
<tr>
<td height="44" colspan="2"><input class="resetbutton" name="btnreset" type="reset" value="بازنویسی" /></td>
</tr>
<tr>
<td height="377" colspan="2">
<table width="200" border="0" align="center" cellpadding="5" cellspacing="5" class="table">
<?php if(isset($msg)){?>
<tr>
<td colspan="2" align="center" valign="top"><?php echo $msg;?></td>
</tr>
<?php } ?>
<tr>


<td><a href='javascript: refreshCaptcha();'><img src="images/search_icon.png" width="24px" height="24px"/></a>
<img src="phpcaptcha/captcha.php?rand=<?php echo rand();?>" id='captchaimg'><br><br>
<label for='message' dir="rtl" class="lable_1">لطفا کد امنیتی را وارد کنید:</label>
<br>


<input style="width:180px;height:25px;font-size:12pt" maxlength="10" id="captcha_code" name="captcha_code" type="text">
<br>
</td>
</tr>
<tr>
<td><input style="width:185px;height:40px" name="Submit" type="submit" onclick="return validate();" value="ثبت" class="button1"></td>
</tr>
</table>
</td>
</tr>
</table>
</form>






<script type="text/javascript">
var sprytextfield1 = new Spry.Widget.ValidationTextField("sprytextfield1");
var sprytextfield2 = new Spry.Widget.ValidationTextField("sprytextfield2", "email");
var sprytextfield3 = new Spry.Widget.ValidationTextField("sprytextfield3", "phone_number");
var sprytextarea1 = new Spry.Widget.ValidationTextarea("sprytextarea1", {maxChars:500, minChars:30, useCharacterMasking:false});
var sprytextfield5 = new Spry.Widget.ValidationTextField("sprytextfield5");
var sprytextarea2 = new Spry.Widget.ValidationTextarea("sprytextarea2", {isRequired:false, maxChars:200});
</script>
</body>
</html>

-سیّد-
پنج شنبه 03 اردیبهشت 1394, 06:34 صبح
مرسی از راهنماییتون ولی من فرمم رو با برنامه dreamweaver طراحی کردم و همونجا هم با امکانات اعتبار سنجی جاوااسکریپت خوده برنامه فرمم رو اعتبار سنجی کردم ,ولی این کد امنیتی رو با php نوشتم و اعتبار سنجی کردم حالا نمیدونم چطوری این دوتا رو به هم ربط بدم



<?php session_start();
if(isset($_POST['Submit'])){
// code for check server side validation
if(empty($_SESSION['captcha_code'] ) || strcasecmp($_SESSION['captcha_code'], $_POST['captcha_code']) != 0 ){
$msg= "<span style='color:#f7601d;font-size:14pt;font-family:yekan'>کد امنیتی صحیح نیست</span>";// Captcha verification is incorrect.
}else{// Captcha verification is Correct. Final Code Execute here!
$msg="<span style='color:green'>The Validation code has been matched.</span>";
}
}
?>







<!DOCTYPE html>


<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />


<title>Untitled Document</title>


<script src="SpryAssets/SpryValidationTextField.js" type="text/javascript"></script>
<script src="SpryAssets/SpryValidationTextarea.js" type="text/javascript"></script>
<link href="SpryAssets/SpryValidationTextField.css" rel="stylesheet" type="text/css" />
<link href="SpryAssets/SpryValidationTextarea.css" rel="stylesheet" type="text/css" />
<link href="phpcaptcha/css/style.css" rel="stylesheet" type="text/css" />
<script type='text/javascript'>
function refreshCaptcha(){
var img = document.images['captchaimg'];
img.src = img.src.substring(0,img.src.lastIndexOf("?"))+"?rand="+Math.random()*1000;
}




</script>
</head>


<body>
<form dir="rtl" id="form1" name="form1" method="post" action="">


<table class="momtable" width="682" cellpadding="3" cellspacing="15" dir="rtl">
<tr>
<td width="322">عنوان آگهی:</td>
<td width="301"><span id="sprytextfield1">
<label for="onvan"></label>
<input type="text" name="onvan" id="onvan" maxlength="38 chars"/>
<span class="textfieldRequiredMsg">لطفا عنوان آگهی را وارد کنید.</span></span></td>
</tr>
<tr>
<td>متن آگهی:</td>
<td><span id="sprytextarea1">
<textarea name="txtName2" id="txtName2"></textarea>
<span class="textareaRequiredMsg">لطفا متن آگهی را وارد نمایید.</span><span class="textareaMaxCharsMsg">کاراکترها بیشتر از 500 حرف مجاز نیست.</span><span class="textareaMinCharsMsg">کاراکترهای کمتر از 30 حرف ،مجاز نیست.</span></span></td>
</tr>
<tr>
<td>نام شرکت:</td>
<td><input class="unrequired" type="text" name="txtFamily2" id="txtFamily2" maxlength="38 chars"/></td>
</tr>
<tr>
<td align="right">نام و نام خانوادگی:</td>
<td><input class="unrequired" type="text" name="txtFamily3" id="txtFamily3" maxlength="25 chars"/></td>
</tr>
<tr>
<td>شهر:</td>
<td><input type="text" name="textfield" id="textfield" maxlength="20 chars"/></td>
</tr>
<tr>
<td>آدرس:</td>
<td><label for="address"></label>
<span id="sprytextarea2">
<textarea name="address" id="address"></textarea>
<span class="textareaMaxCharsMsg">Exceeded maximum number of characters.</span></span></td>
</tr>
<tr>
<td>تلفن تماس:</td>
<td><label for="phon"></label>
<label for="phon"></label>
<span id="sprytextfield5">
<input type="text" name="phon" id="phon" />
<span class="textfieldRequiredMsg">لطفا شماره تماس خود
را وارد کنید.</span></span></td>
</tr>
<tr>
<td>موبایل:</td>
<td><span id="sprytextfield3">
<label for="mobile"></label>
<input type="text" name="mobile" id="mobile" />
<span class="textfieldRequiredMsg">لطفا شماره موبایل خود را واردکنید.</span><span class="textfieldInvalidFormatMsg">شماره موبایل صحیح نیست.</span></span></td>
</tr>
<tr>
<td>ایمیل:</td>
<td><span id="sprytextfield2">
<input type="text" name="textfield5" id="textfield5" value=""/>
<span class="textfieldRequiredMsg">لطفا نشانی ایمیل خود
را وارد کنید.</span><span class="textfieldInvalidFormatMsg">نشانی ایمیل نامعتبر است.</span></span></td>
</tr>
<tr>
<td height="44" colspan="2"><input class="resetbutton" name="btnreset" type="reset" value="بازنویسی" /></td>
</tr>
<tr>
<td height="377" colspan="2">
<table width="200" border="0" align="center" cellpadding="5" cellspacing="5" class="table">
<?php if(isset($msg)){?>
<tr>
<td colspan="2" align="center" valign="top"><?php echo $msg;?></td>
</tr>
<?php } ?>
<tr>


<td><a href='javascript: refreshCaptcha();'><img src="images/search_icon.png" width="24px" height="24px"/></a>
<img src="phpcaptcha/captcha.php?rand=<?php echo rand();?>" id='captchaimg'><br><br>
<label for='message' dir="rtl" class="lable_1">لطفا کد امنیتی را وارد کنید:</label>
<br>


<input style="width:180px;height:25px;font-size:12pt" maxlength="10" id="captcha_code" name="captcha_code" type="text">
<br>
</td>
</tr>
<tr>
<td><input style="width:185px;height:40px" name="Submit" type="submit" onclick="return validate();" value="ثبت" class="button1"></td>
</tr>
</table>
</td>
</tr>
</table>
</form>






<script type="text/javascript">
var sprytextfield1 = new Spry.Widget.ValidationTextField("sprytextfield1");
var sprytextfield2 = new Spry.Widget.ValidationTextField("sprytextfield2", "email");
var sprytextfield3 = new Spry.Widget.ValidationTextField("sprytextfield3", "phone_number");
var sprytextarea1 = new Spry.Widget.ValidationTextarea("sprytextarea1", {maxChars:500, minChars:30, useCharacterMasking:false});
var sprytextfield5 = new Spry.Widget.ValidationTextField("sprytextfield5");
var sprytextarea2 = new Spry.Widget.ValidationTextarea("sprytextarea2", {isRequired:false, maxChars:200});
</script>
</body>
</html>







اول از همه: لطف کنید کد HTML رو توی سایت داخل تگ HTML بذارید تا syntax-highlight بشه و راحت‌تر بشه خوندش.
کد PHP تون هم همه‌اش توی یه خط اومده بود و به هم ریخته بود.

۲ تا نکته اینجا وجود داره:
یکی این که captcha رو validate کنید، و دیگری این که بقیه‌ی field ها رو validate کنید.
برای validate کردن بقیه‌ی فیلدها، خوب هر جور که دوست دارید validate شون کنید (با یه تعداد if یا با روش‌های پیچیده‌تر، مثل استفاده از validator ها). در نهایت یا مقادیر فیلدها اوکی هست، یا نیست. اگه نیست، باید یه پیغام خطا به کاربر نشون بدید. اگه هست، باید کار رو ادامه بدید (مثلاً توی پایگاه داده درج کنید) و یه پیغام به کاربر بدید که اوکی شد.
اما برای captcha به صورت خاص، با توجه به روشی که توی کد بالا انتخاب کردید (استفاده از session برای نگهداری مقدار صحیح captcha)، توی بخشی که captcha رو می‌سازید (یعنی فایل phpcaptcha/captcha.php) باید مقدار صحیح captcha رو داخل session ذخیره کنید، و توی کد validation تون اون رو بررسی کنید (که این بخش کار توی کد بالا انجام شده).
فقط اشکالی که توی کد بالا می‌بینم اینه که msg رو هیچ کاری نکردید! یعنی مقدار msg توی کد php به دست اومده، و توی پایینی که HTML زدید ازش استفاده کردید. خوب یکی این که پایینی PHP به نظر می‌رسه نه HTML. و دوم این که این دو تا کدی که نوشتید، به نظر می‌رسه یه کد باشن. یعنی اون بخش PHP بالایی رو باید بالای بخش HTML پایینی توی همون فایل بذارید.

در نهایت یه اشکال امنیتی توی کدتون وجود داره: وقتی که فرم برای سرور فرستاده شد و مقدار captcha بررسی شد، از نظر امنیتی بهتره که مقدار درست captcha رو بلافاصله از داخل session پاک کنید:

unset($_SESSION['captcha_code']);

ساراعلی
پنج شنبه 03 اردیبهشت 1394, 12:10 عصر
خدمتتون توضیح دادم که فیلدها رو با جاوااسکریپت validat کردم و اون پیغام خطا را به کاربر نشون میده !! و تیکه کد php بالا رو در ابتدای کد html قرار دادم ،اینجا جدا از هم نشون میده !در واقع یک فایل php هست کلش!! فقط مشکلم اینه که وقتی روی دکمه submit کلیک میکنم اگر فیلدها صحیح پر شده باشن ولی کد امنیتی غلط وارد شده باشه مقدار داخل فیلدها پاک میشه و فقط پیغام مربوط به کد امنیتی " کد امنیتی صحیح نیست" رو نشون میده... من هنوز پایگاه داده رو نساختم اینکه مقدار فیلدها پاک میشه یعنی چی؟؟ با توجه به اینکه مقدار action خالی هست

-سیّد-
پنج شنبه 03 اردیبهشت 1394, 13:24 عصر
فقط مشکلم اینه که وقتی روی دکمه submit کلیک میکنم اگر فیلدها صحیح پر شده باشن ولی کد امنیتی غلط وارد شده باشه مقدار داخل فیلدها پاک میشه و فقط پیغام مربوط به کد امنیتی " کد امنیتی صحیح نیست" رو نشون میده... من هنوز پایگاه داده رو نساختم اینکه مقدار فیلدها پاک میشه یعنی چی؟؟ با توجه به اینکه مقدار action خالی هست
اولاً وقتی action مقدارش خالی باشه، فرم رو که submit می‌کنید به صفحه‌ای که توش هست فرستاده می‌شه. یعنی اگه توی فایل test.php یه فرم بذارید که action اش خالی باشه، به خود test.php فرستاده می‌شه.

ثانیاً دلیل این که مقدار فیلدها خالی می‌شه، اینه که input هایی که دارید بدون value هستند. در نتیجه صفحه که بارگذاری می‌شه، همه‌شون بدون مقدار می‌شن. اگه می‌خواین مقدار قبلی توشون بمونه، باید براشون value بذارید:

<input type="text" name="onvan" id="onvan" maxlength="38 chars" value="<?= @$_POST['onvan'] ?>" />
البته دقت کنید که این کاری که اینجا کردم، از نظر امنیتی مشکل داره (مشکل XSS). من فقط برای مثال این رو گذاشتم.
همچنین ممکنه دستور =?> روی سیستم شما فعال نباشه، در این صورت می‌تونید از ... echo ?> استفاده کنید.

ثالثاً اگه کل فایل php مورد نظر همینه که اینجا گذاشتید، خوب الان که هیچ کاری به پایگاه داده نداره. در کل فرمی که نمایش داده می‌شه، هیچ ارتباطی به پایگاه داده نداره، مگر این که شما ارتباطشون رو برقرار کنید.

ساراعلی
پنج شنبه 03 اردیبهشت 1394, 18:03 عصر
بازم تشکر از شما.. اگه میگین از نظر امنیتی مشکل داره پس نمیشه استفاده کرد!! در ضمن روی textarea کار نمیکنه یعنی باز مقدار فیلدشو خالی میکنه!! و دکمه بازنویسی یا همون reset هم گاهی کار نمیکنه!! اگه مقدار action برابر با این باشه از نظر امنیت تاثیری داره؟؟


action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"


چیکار کنم پس:ناراحت:

-سیّد-
پنج شنبه 03 اردیبهشت 1394, 23:00 عصر
اگه میگین از نظر امنیتی مشکل داره پس نمیشه استفاده کرد!!

برای رفع مشکل XSS، علی‌الحساب می‌تونید از تابع htmlentities (http://php.net/manual/en/function.htmlentities.php) یا همون htmlspecialchars (http://php.net/manual/en/function.htmlspecialchars.php) که خودتون بهش اشاره کردید استفاده کنید. اینجا بحثش رو باز نمی‌کنم چون یه مقدار خارج از تاپیک می‌شه. همون مثال بالایی با استفاده از htmlentities:


<input type="text" name="onvan" id="onvan" maxlength="38 chars" value="<?= @htmlentities($_POST['onvan']) ?>" />




در ضمن روی textarea کار نمیکنه یعنی باز مقدار فیلدشو خالی میکنه!! و دکمه بازنویسی یا همون reset هم گاهی کار نمیکنه!!

دلیل این که روی textarea کار نمی‌کنه اینه که textarea مثل input دارای attribute ای به نام value نیست، بلکه داده‌اش به صورت text به عنوان child اش قرار می‌گیره (اگه دقت کرده باشید textarea بر خلاف ‌input باید با <textarea/> بسته بشه):


<textarea name="txtName2" id="txtName2"><?= @htmlentities($_POST['txtName2']) ?></textarea>




اگه مقدار action برابر با این باشه از نظر امنیت تاثیری داره؟؟


action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"


شما توی این بخش مشکل امنیت نداشتید که بخواین حلش بکنید! در نتیجه اینجا استفاده از htmlspecialchars اضافیه. یعنی کلاً action رو می‌تونید خالی بذارید و تأثیری توی امنیت نداره. اگه یه وقتی خواستید به هر دلیلی action رو اینجا بذارید، بله تأثیر داره (به خاطر این که مقداری که می‌خواین echo کنین، ممکنه شامل کوتیشن و تگ‌های html باشه و باعث XSS بشه).

ساراعلی
شنبه 05 اردیبهشت 1394, 09:43 صبح
اول از همه: لطف کنید کد HTML رو توی سایت داخل تگ HTML بذارید تا syntax-highlight بشه و راحت‌تر بشه خوندش.
کد PHP تون هم همه‌اش توی یه خط اومده بود و به هم ریخته بود.

۲ تا نکته اینجا وجود داره:
یکی این که captcha رو validate کنید، و دیگری این که بقیه‌ی field ها رو validate کنید.
برای validate کردن بقیه‌ی فیلدها، خوب هر جور که دوست دارید validate شون کنید (با یه تعداد if یا با روش‌های پیچیده‌تر، مثل استفاده از validator ها). در نهایت یا مقادیر فیلدها اوکی هست، یا نیست. اگه نیست، باید یه پیغام خطا به کاربر نشون بدید. اگه هست، باید کار رو ادامه بدید (مثلاً توی پایگاه داده درج کنید) و یه پیغام به کاربر بدید که اوکی شد.
اما برای captcha به صورت خاص، با توجه به روشی که توی کد بالا انتخاب کردید (استفاده از session برای نگهداری مقدار صحیح captcha)، توی بخشی که captcha رو می‌سازید (یعنی فایل phpcaptcha/captcha.php) باید مقدار صحیح captcha رو داخل session ذخیره کنید، و توی کد validation تون اون رو بررسی کنید (که این بخش کار توی کد بالا انجام شده).
فقط اشکالی که توی کد بالا می‌بینم اینه که msg رو هیچ کاری نکردید! یعنی مقدار msg توی کد php به دست اومده، و توی پایینی که HTML زدید ازش استفاده کردید. خوب یکی این که پایینی PHP به نظر می‌رسه نه HTML. و دوم این که این دو تا کدی که نوشتید، به نظر می‌رسه یه کد باشن. یعنی اون بخش PHP بالایی رو باید بالای بخش HTML پایینی توی همون فایل بذارید.

در نهایت یه اشکال امنیتی توی کدتون وجود داره: وقتی که فرم برای سرور فرستاده شد و مقدار captcha بررسی شد، از نظر امنیتی بهتره که مقدار درست captcha رو بلافاصله از داخل session پاک کنید:

unset($_session['captcha_code']);

ببخشید اینکه گفتید
بهتره که مقدار درست captcha رو بلافاصله از داخل session پاک کنید:

unset($_session['captcha_code']);

یعنی این تیکه کد رو کجا باید قرار بدم دقیقا؟؟

یه سوال دیگه اینکه حالا که من فیلدها رو با جاوااسکریپت validate کردم و کد امنیتی رو با php ! به نظر شما این روش کافیه؟ یا بازم تاکید دارید که از جاوااسکریپت برای اعتبارسنجی فرمم استفاده نکنم!

-سیّد-
شنبه 05 اردیبهشت 1394, 11:21 صبح
ببخشید اینکه گفتید
بهتره که مقدار درست captcha رو بلافاصله از داخل session پاک کنید:

unset($_session['captcha_code']);

یعنی این تیکه کد رو کجا باید قرار بدم دقیقا؟؟

اولاً که من یه سوتی دادم: اسم متغیر session با حروف بزرگ هست:

unset($_SESSION['captcha_code']);
(بالاتر هم ویرایش کردم و درستش کردم)

ثانیاً این کار رو باید بعد از این که فرم برای شما فرستاده شد انجام بدید. یعنی چه captcha رو درست وارد کرده بود، چه اشتباه وارد کرده بود، شما باید این مقدار رو از توی session پاک کنید. بنابراین مثلاً می‌تونید همون اول کد php تون (البته بعد از if اول که یعنی دارید درخواست کاربر رو بررسی می‌کنید) همونجا که مقدار مورد نظر رو از توی session می‌خونید، بلافاصله پاکش کنید. یعنی مثلاً به جای

if(empty($_SESSION['captcha_code'] ) || strcasecmp($_SESSION['captcha_code'], $_POST['captcha_code']) != 0 ){
بنویسید:


$correct_captcha = @$_SESSION['captcha_code'];
unset($_SESSION['captcha_code'];
if (strcasecmp($correct_captcha, $_POST['captcha_code']) != 0) {
...
}

دقت کنید که استفاده از علامت @ باعث می‌شه حالتی که اصلاً این مقدار توی session وجود نداره هم پوشش داده بشه (قبلاً شما با استفاده از تابع empty این حالت رو بررسی کرده بودید).



یه سوال دیگه اینکه حالا که من فیلدها رو با جاوااسکریپت validate کردم و کد امنیتی رو با php ! به نظر شما این روش کافیه؟ یا بازم تاکید دارید که از جاوااسکریپت برای اعتبارسنجی فرمم استفاده نکنم!


من اصلاً نگفتم با جاوا اسکریپت اعتبارسنجی نکنید! اتفاقاً می‌گم حتماً با جاوا اسکریپت این کار رو بکنید، چون خیلی به کاربر حس خوبی می‌ده. من فقط حرفم این بود که این کار اصلاً کافی نیست (نه این که لازم نیست).
باز هم این رو تکرار می‌کنم: اعتبارسنجی توسط javascript به هیچ وجه نمی‌تونه امنیت شما رو تضمین کنه. ولی می‌تونه به سرعت اشتباهات تایپی کاربر رو بهش گوشزد کنه و این خیلی خوبه.

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

در نتیجه بهترین روش اینه: هم جاوااسکریپتی اعتبارسنجی کنید، هم سمت سرور. البته captcha رو نمی‌تونید سمت جاوا اسکریپت اعتبارسنجی کنید، پس فقط این یه مورد هست که تنها سمت سرور انجام می‌شه.

ساراعلی
شنبه 05 اردیبهشت 1394, 11:32 صبح
خب بالاخره من متوجه نشدم الان با این تفاسیر و کدهای پروژهام که میبینید من باید کار دیگه ای انجام بدم یا نه؟؟ چطوری هم با جاوااسکریپت هم سمت سرور اعتبار سنجی کنم؟

-سیّد-
شنبه 05 اردیبهشت 1394, 12:24 عصر
خب بالاخره من متوجه نشدم الان با این تفاسیر و کدهای پروژهام که میبینید من باید کار دیگه ای انجام بدم یا نه؟؟ چطوری هم با جاوااسکریپت هم سمت سرور اعتبار سنجی کنم؟
شما الان با جاوااسکریپت اعتبارسنجی کردید، درسته؟ پس برای اعتبارسنجی جاوااسکریپت لازم نیست کار دیگه‌ای انجام بدید.
تنها چیزی که می‌مونه سمت سرور هست. مثلاً شما برای فیلد onvan حداکثر طول رو برابر ۳۸ در نظر گرفته‌اید:

<input type="text" name="onvan" id="onvan" maxlength="38 chars"/>
خوب سمت سرورش مثلاً می‌شه اینطوری: (این فقط یک راه برای انجام این کار هست، ممکنه شما بخواین از روش‌های دیگه استفاده کنید)
می‌تونید یه آرایه تعریف کنید که پیغام‌های خطای اعتبارسنجی رو توش نگه می‌دارید. هر خطایی که باهاش برخورد کردید، اونجا اضافه می‌کنید و در نهایت هنگام نمایش صفحه، خطاها رو نمایش می‌دید:


$errors = array();

$onvan = @$_POST['onvan'];
if (is_null($onvan)) {
$errors[] = 'لطفاً عنوان را وارد کنید.';
}
elseif (strlen($onvan) > 38) {
$errors[] = 'حداکثر طول ممکن برای عنوان، ۳۸ کاراکتر است.';
}

...

// ‫توی بخش HTML:
<?php if (!empty($errors)): ?>
<div class="errors">
<?php
foreach($errors as $error):
?><div class="error"><?php echo $error; ?></div><?php
endforeach;
?>
</div>
<?php endif; ?>

ساراعلی
یک شنبه 06 اردیبهشت 1394, 10:08 صبح
سلام خیلی خیلی منونم از راهماییهای مفیدتون تا الان ولی من هنوز همون مشکل اولی رو دارم یعنی چون فیلدهای فرمم را با جاوااسکریپت اعتبار سنجی کردم و کد امنیتی رو با php الان که دکمه submit رو میزنم بدون اعتنا به صحت یا خالی بودن کد امنیتی وارد صفحه ای که در action تعریف میکنم میشه اشکال کارم کجاست؟؟ خواهش میکنم کمک کنید خیلی وقتمو گرفته این مسئله

-سیّد-
یک شنبه 06 اردیبهشت 1394, 10:18 صبح
سلام خیلی خیلی منونم از راهماییهای مفیدتون تا الان ولی من هنوز همون مشکل اولی رو دارم یعنی چون فیلدهای فرمم را با جاوااسکریپت اعتبار سنجی کردم و کد امنیتی رو با php الان که دکمه submit رو میزنم بدون اعتنا به صحت یا خالی بودن کد امنیتی وارد صفحه ای که در action تعریف میکنم میشه اشکال کارم کجاست؟؟ خواهش میکنم کمک کنید خیلی وقتمو گرفته این مسئله
خوب اشکال اینجاست که شما می‌خواین در صورت خالی یا اشتباه بودن کد امنیتی، مرورگر به صفحه‌ی بعد نره. البته این کار با استفاده از AJAX امکان‌پذیر هست، ولی فعلاً اون رو بی‌خیال می‌شیم و با روش ساده جلو می‌ریم.

روش کار اینه که شما فرم رو به همون صفحه که توش هستید می‌فرستید، نه به صفحه‌ی مقصد اصلی.
یعنی فرض کنید دارید یه صفحه‌ی لاگین می‌نویسید: login.php
توی این صفحه یه فرم می‌ذارید که action اش هست خودش (مثل بالا می‌تونید action رو خالی بذارید).
حالا توی کد صفحه، اولش چک می‌کنید که اطلاعات درست هست یا نه. اگه درست نبود، یه سری پیغام نشون می‌دید. (تا اینجاش شد همین کدی که بالاتر زدید)
اما اگه درست بود، می‌تونید redirect کنید به صفحه‌ی اصلی. (این بخش می‌شه همون بخش از کد که این کامنت توش بود:

// Captcha verification is Correct. Final Code Execute here!
)
توی اون صفحه‌ی اصلی هم اولش چک می‌کنید که طرف لاگین کرده باشه و اگر نکرده باشه می‌فرستیدش به صفحه‌ی لاگین.

پس روند کار اینطوری می‌شه:

اگه اطلاعات درست وارد بشه:

login.php => ورود اطلاعات صحیح => login.php => چک شدن اطلاعات و redirect به صفحه‌ی بعد => home.php => چک شدن این که لاگین شده یا نه (مثلاً با session یا پایگاه داده)، و چون لاگین شده، نمایش اطلاعات اصلی


اگه اطلاعات غلط وارد بشه:

login.php => ورود اطلاعات غلط => login.php => چک شدن اطلاعات و نمایش خطاها

اگه یه نفر ژانگولر بزنه و یه ضرب بیاد به home.php:

home.php => چک شدن این که لاگین شده یا نه، و چون لاگین نشده، redirect به صفحه‌ی لاگین => login.php => ...

ساراعلی
یک شنبه 06 اردیبهشت 1394, 10:31 صبح
اینطوری که شما میگید اگه کاربر فیلدها رو پر کرده باشه وقتی به صفحه بعد میره و دوباره برمیگرده اطلاعاتش رو دوباره از اول باید وارد کنه اینجوری که کلا از خیرش میگذره!!

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

-سیّد-
یک شنبه 06 اردیبهشت 1394, 13:12 عصر
اینطوری که شما میگید اگه کاربر فیلدها رو پر کرده باشه وقتی به صفحه بعد میره و دوباره برمیگرده اطلاعاتش رو دوباره از اول باید وارد کنه اینجوری که کلا از خیرش میگذره!!
متوجه نشدم منظورتون کدوم حالت هست.
اگه حالتی هست که کاربر اطلاعات رو درست وارد کرده و شما توی پایگاه داده واردشون کردید، که دیگه نیازی نیست برگرده به اون صفحه.
اگه حالتی هست که اطلاعات رو اشتباه وارد کرده (یا فرض کنیم فقط captcha رو اشتباه وارد کرده)، خوب اینجا دیگه redirect ای رخ نمی‌ده و توسط همون value که بالاتر گفتم مقادیر قبلی فیلدها سر جاشون هستن.


login.php => ورود اطلاعات غلط => login.php => چک شدن اطلاعات و نمایش خطاها

اینجا همچنان توی صفحه‌ی login.php موندیم و هیچ redirect ای نداریم. در نتیجه مقادیر قبلی توی POST_$ موجود هستند.

ساراعلی
سه شنبه 08 اردیبهشت 1394, 21:03 عصر
اولاً وقتی action مقدارش خالی باشه، فرم رو که submit می‌کنید به صفحه‌ای که توش هست فرستاده می‌شه. یعنی اگه توی فایل test.php یه فرم بذارید که action اش خالی باشه، به خود test.php فرستاده می‌شه.

ثانیاً دلیل این که مقدار فیلدها خالی می‌شه، اینه که input هایی که دارید بدون value هستند. در نتیجه صفحه که بارگذاری می‌شه، همه‌شون بدون مقدار می‌شن. اگه می‌خواین مقدار قبلی توشون بمونه، باید براشون value بذارید:

<input type="text" name="onvan" id="onvan" maxlength="38 chars" value="<?= @$_POST['onvan'] ?>" />
البته دقت کنید که این کاری که اینجا کردم، از نظر امنیتی مشکل داره (مشکل XSS). من فقط برای مثال این رو گذاشتم.
همچنین ممکنه دستور =?> روی سیستم شما فعال نباشه، در این صورت می‌تونید از ... echo ?> استفاده کنید.

ثالثاً اگه کل فایل php مورد نظر همینه که اینجا گذاشتید، خوب الان که هیچ کاری به پایگاه داده نداره. در کل فرمی که نمایش داده می‌شه، هیچ ارتباطی به پایگاه داده نداره، مگر این که شما ارتباطشون رو برقرار کنید.


ببخشید یک سوال دیگه در همین مورد داشتم برای حفظ مقدار تگ select در فرم که با php اعتبار سنجی شده چیکار کنم؟ وقتی روی دکمه submit میزنم در مورد اشتباهات بقیه فیلدها اخطار میده و تگ select رو هم خالی میکنه با اینکه یک ایتم انتخاب کردم!!

-سیّد-
چهارشنبه 09 اردیبهشت 1394, 11:00 صبح
ببخشید یک سوال دیگه در همین مورد داشتم برای حفظ مقدار تگ select در فرم که با php اعتبار سنجی شده چیکار کنم؟ وقتی روی دکمه submit میزنم در مورد اشتباهات بقیه فیلدها اخطار میده و تگ select رو هم خالی میکنه با اینکه یک ایتم انتخاب کردم!!

برای تگ select، باید اون option ای که انتخاب شده، attribute ای به نام selected داشته باشه (که معمولاً مقدارش رو هم selected می‌ذارن):


<select name="test">
<option value="1">اولی</option>
<option value="2" selected="selected">دومی</option>
<option value="3">سومی</option>
</select>