<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>insanesecurity &#187; CAPTCHA</title>
	<atom:link href="http://insanesecurity.info/blog/tag/captcha/feed" rel="self" type="application/rss+xml" />
	<link>http://insanesecurity.info/blog</link>
	<description>security through a distorted eye</description>
	<lastBuildDate>Thu, 25 Feb 2010 22:31:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>8 Tips For A Secure Login Script/Admin Panel</title>
		<link>http://insanesecurity.info/blog/8-tips-for-a-secure-login-scriptadmin-panel</link>
		<comments>http://insanesecurity.info/blog/8-tips-for-a-secure-login-scriptadmin-panel#comments</comments>
		<pubDate>Wed, 24 Jun 2009 16:53:57 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[CAPTCHA]]></category>
		<category><![CDATA[Encryption]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=76</guid>
		<description><![CDATA[After reading the title you may say to yourself &#8220;Oh no, another &#60;&#60;secure login script&#62;&#62; article! Aren&#8217;t there enough already online?&#8221;. Yes there are, but unfortunately many tutorials (if it&#8217;s appropriate to call them so) only show you how to write SQL Injection free code. But that isn&#8217;t enough. What about brute force (dictionary, hybrid) [...]]]></description>
			<content:encoded><![CDATA[<p>After reading the title you may say to yourself &#8220;Oh no, another &lt;&lt;secure login script&gt;&gt; article! Aren&#8217;t there enough already online?&#8221;. Yes there are, but unfortunately many tutorials (if it&#8217;s appropriate to call them so) only show you how to write SQL Injection free code. But that isn&#8217;t enough. What about brute force (dictionary, hybrid) attacks? Or how about making your admin panel (user panel) CSRF free? Well this article will try to deal with those issues too.</p>
<p><span id="more-76"></span></p>
<h2>Tip 1: Login Page/Authentication</h2>
<p>Let&#8217;s start with the basic example, which you can find in all those so similar tutorials&#8230; First of is the login form:</p>
<pre>
&lt;form action="login.php" method="post"&gt;
    &lt;input type="text" name="username" /&gt;
    &lt;input type="password" name="password" /&gt;

    &lt;input type="submit" name="Login" /&gt;
&lt;/form>
</pre>
<p>Very complex html code, I know. It took me around 10 minutes to write it. Now for the php script that does all the work. <strong>NOTE</strong>: In this example and all to follow we always assume a mysql connection has been made and that sessions are started.</p>
<pre>
$username = mysql_real_escape_string($_POST['username']);
$password = sha1('salt'.$_POST['password']);
$result = mysql_query(
    "SELECT id
     FROM users
     WHERE username='$username' AND password='$password'
     ORDER BY id"
);
if(1!=mysql_num_rows($result)) {
    echo 'Login failed, username or password was wrong!';
    exit;
}
$_SESSION['auth'] = true;
$_SESSION['username'] = $username;
$_SESSION['id'] = mysql_result($result, 0);
echo 'Logged in!';
</pre>
<p>If everything is clear till now than we can move onward&#8230; (with this first section I&#8217;ve done a summary of all the secure login scripts tutorials)</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h2>Tip 2: Bruteforce?</h2>
<p>Such a rudimentary attack that people almost forget about it. And most of the time it can be invisible to the websites administrator because POST requests aren&#8217;t logged by default. You may remember this from my article <a href="http://insanesecurity.info/2009/01/logging-the-http-requests/">Logging the HTTP requests!</a> But I&#8217;m not going to use that, because I want to keep all this simple, as simple as possible. So then, we will assume we got a table which is cleared daily (cron?) and stores only the username in the table. One columned table. (I told you that I&#8217;m gonna keep it simple) Then the following lines would be also in the login script (before the login query):</p>
<pre>
$counter = mysql_result(
    mysql_query(
        "SELECT COUNT(*)
         FROM attempts
         WHERE username='$username'"
    ),
    0
);
mysql_query("INSERT INTO attempts VALUES('$username')");
if($counter&gt;=10) {
    echo 'Bruteforce attempt detected or more than allowed logins per day exceeded!';
    exit;
}
</pre>
<p>As you can see the drawback for this is that while protecting the users from bruteforce attacks, it may also (and it&#8217;s likely) to lock them out. Luckily for us there is a solution for the problem. We add another column to our table <strong>attempts</strong> of type char(2) in which we store the current hour. Basically we limit the number of logins per hour.</p>
<pre>
$counter = mysql_result(
    mysql_query(
        "SELECT COUNT(*)
         FROM attempts
         WHERE username='$username'
         AND hour='".date('G')."'"
    ),
    0
);
mysql_query("INSERT INTO attempts VALUES('$username', '".date('G')."')");
if($counter&gt;=3) {
    echo 'Max number of logins per hour exceeded!';
    exit;
}
</pre>
<p>Now it looks a little better, but still it misses something&#8230;</p>
<h2>Tip 3: IP Ban List</h2>
<p>You could use ban lists for various reasons, from allowing &#8220;known attackers&#8221; to blocking access via proxy. Generally people tend to use .htaccess files for blacklisting, but I will stick to PHP and MySQL for the example. <strong>NOTE</strong>: On medium to large websites a database (MySQL) &#8211; backend (PHP) application would stress pretty much the database. The following code should be inserted before the max number of logins per hour check.</p>
<pre>
$max_counter = mysql_result(
    mysql_query(
        "SELECT COUNT(*)
         FROM attempts
         WHERE username='$username'"
    ),
    0
);
if($max_counter&gt;9) {
    mysql_query("INSERT INTO banlist VALUES('".$_SERVER['REMOTE_ADDR']."')");
}
</pre>
<p>And the following line on the first line of the script.</p>
<pre>
if(1==mysql_num_rows(
    mysql_query(
        "SELECT 1
         FROM banlist
         WHERE ip='".$_SERVER['REMOTE_ADDR']."'"
    )
)) {
    echo 'Your IP address is in the ban list!';
    exit;
}
</pre>
<p>Of course you could dump the IP Address list from time to time from the database, but the following solution is a better one because it does not involve high stress on database.<br />
<script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h2>Tip 4: reCAPTCHA</h2>
<p>CAPTCHA is a good way to protect a web page (login page, important forms) from bruteforce and CSRF attacks. But we are not talking about self made CAPTCHA&#8217;s, you don&#8217;t have to reinvent the wheel&#8230; in a cubic form. That&#8217;s right, most of those who write there own CAPTCHA&#8217;s tend to make them weak or impossible to use (yes, Rapidshare&#8217;s CAPTCHA is one of those). You should use a good and public CAPTCHA, like reCAPTCHA. Also don&#8217;t over use them, you have to think of CAPTCHA&#8217;s like door keys. It&#8217;s very good to have one to your entrance door, but having to unlock the door for every room can be quite annoying, if not frustrating.</p>
<h2>Tip 5: Encrypted login information</h2>
<p>You either should use SSL or (if not available) frontend encryption (hashing in our case). A good example of such an implementation would be <a href="http://insanesecurity.info/2009/01/useratuh-frontend-to-backend-encryption/">userAtuh</a>&#8217;s one. You can find available md5/sha1 hashing library&#8217;s written in javascript around the web. One such an example is Paul Johnston&#8217;s <a href="http://pajhome.org.uk/crypt/md5/md5src.html">Javascript MD5</a> library which is stated to be used by Yahoo on several non SSL pages. Can&#8217;t tell if it&#8217;s true or not, didn&#8217;t check it out, but for those who know Trilulilu (especially Romanian comrades) I can tell you that they implemented it in their flash player, for &#8220;encrypting&#8221; the source of their media (did I say too much?=).</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h2>Tip 6: Legitimate Requests (CSRF free)</h2>
<p>As mentioned before excessively using CAPTCHA may be annoying, except in the case that the admin panel is designated for only one person (yourself) and you can bare completing on every important request a CAPTCHA field. For the other cases you could take a similar approach. On request of a page with an important form you could generate the token in the following way.</p>
<pre>
$_SESSION['token'] = sha1(rand());
</pre>
<p>And inside the form you could place it like&#8230;</p>
<pre>
&lt;input type="hidden" name="token" value="&lt;?php echo $_SESSION['token']; ?&gt;" /&gt;
</pre>
<p>While in the form processing page you should deal with it as in the following code.</p>
<pre>
if($_SESSION['token']!=$_POST['token']) {
    exit;
}
$_SESSION['token'] = sha1(rand());
</pre>
<p>Also a better way would be by using mt_rand() and seeding it with a secret method. Like for example the sum of the numbers from the session id.</p>
<h2>Tip 7: Protect your includes/secure pages</h2>
<p>If you develop your web application in a similar manner as myself than probably you include the admin pages, rather than use one  single over bloated file. And it&#8217;s a common mistake to not protect those files from direct access. I&#8217;ve seen cases of obscure naming of the files, which are not secure if the attacker can get directory information in a way or another. Although are very interesting. Why? Because security by obscurity can be very fun an creative, even useful sometimes if build on top of a secure design. Like for example when using a MySQL database (version 4, so no information_schema database available) and obscuring the table names. Coming back to our subject, you could protect your included files by using the following line of code.</p>
<pre>
if(!defined('PROTECTED')) { exit; }
</pre>
<p>While defining the PROTECTED constant in the script which includes the files (which we assume you protect). You can secure your main files (those who include files) in a similar way.</p>
<pre>
if(!$_SESSION['auth']) { exit; }
define('PROTECTED', true);
</pre>
<h2>Tip 8: Password Change</h2>
<p>When making a password change functionality don&#8217;t forget to ask the user for their current password. Many think that if a user is logged in and no CSRF could take place they are safe and thus don&#8217;t need to ask them for their current password. It&#8217;s wrong to think like that because Session Riding attacks are more frequent than you think. And it&#8217;s not such a big deal of doing this, it only takes an extra where clause in the update syntax.</p>
<pre>
$old_password = sha1('salt'.$_POST['old_password']);
$new1 = sha1('salt'.$_POST['new1']);
$new2 = sha1('salt'.$_POST['new2']);
if($new1!=$new2) {
    echo 'Your new passwords do not match!';
    exit;
}
if(mysql_query(
    "UPDATE
     SET password='$new1'
     WHERE id='".$_SESSION['id']."'
     AND password='$old_password'"
)) {
    echo 'Password successfully changed!';
}
else {
    echo 'Password couldn\'t be changed!';
}
</pre>
<h2>Tip 0</h2>
<p>This are the most common approaches which should be taken when coding login scripts/admin panels. Also they are the most common neglected aspects. Kind of paradoxical in a way. And that;s not all, if we think of HTTP Redirects which by the way haven&#8217;t been treated because latest versions of PHP protect you against HTTP Response Splitting. Another thing I didn&#8217;t treat was XSS, which I think (and maybe you would approve) doesn&#8217;t make a part of this subject, it concerns the way you implement functionality in your pages. I often wonder why even give power to the user, like for example in a comment form. Why give him even the ability to post link (and convert them to link)?</p>
<p>Anyway, as you can see I didn&#8217;t post a ready to use script/class because I wanted you to understand the concept behind login/admin panel security. Not just copy-paste the code and cross your fingers that it will work.</p>
<p><strong>UPDATE</strong>: On <a href="http://rvdh.ath.cx/">Ronald</a>&#8217;s suggestion I replaced the md5 hashes with sha1 hashes, even salted them. Also modified the MySQL code to order the result by id, just in case there where two accounts with the same login information (which shouldn&#8217;t, if you properly did the checks in the registration page, if uses any). </p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/8-tips-for-a-secure-login-scriptadmin-panel/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Spam free forms and contact details</title>
		<link>http://insanesecurity.info/blog/spam-free-forms-and-contact-details</link>
		<comments>http://insanesecurity.info/blog/spam-free-forms-and-contact-details#comments</comments>
		<pubDate>Wed, 24 Jun 2009 05:47:38 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[CAPTCHA]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Spam]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/spam-free-forms-and-contact-details</guid>
		<description><![CDATA[I always have been annoyed by things like: the morning alarm clock, long distance travels, undocumented functions and spam. But from all the above mentioned spam as well may be the most annoying one from it, the rest of them don&#8217;t happen that often. And certainly we realize the mass spreading of spam when we [...]]]></description>
			<content:encoded><![CDATA[<p>I always have been annoyed by things like: the morning alarm clock, long distance travels, undocumented functions and spam. But from all the above mentioned spam as well may be the most annoying one from it, the rest of them don&#8217;t happen that often.<br />
<span id="more-17"></span><br />
And certainly we realize the mass spreading of spam when we see the statistics for <a href="http://files.data.timgraham.net.s3.amazonaws.com/tg/blogs/data/wp-content/uploads/amonthofspam.gif">a month of spam</a>. Unfortunately the number of spammers will grow/maintain itself long from now on. Until spammers get paid I can&#8217;t see why they would stop. Hell, some people try making money by <a href="http://www.forward-moving.com/blog/2006/10/12/spam-a-battle-worth-fighting/">trademarking the word spam</a>.</p>
<p>Well, enough said about that, the main issue we are facing is how to reduce the spam we get. I&#8217;m not talking about email protection, or blog protection; I don&#8217;t know how you people consider, but I think Akismet is doing a great job for blogs! I want to talk about those moments when you create a contact/comment page and want to make it spam proof.</p>
<h2>Are you human? (CAPTCHA)</h2>
<p>It seems to be the solution in many cases. But I&#8217;m not talking about making your own CAPTCHA, if you lack the experience. Some did it and it went from &#8217;simple&#8217; to imposible: take a look at <a href="http://www.geeksaresexy.net/2008/04/24/rapidshare-captcha-will-drive-you-crazy/">RapidShare&#8217;s CAPTCHA</a>. Instead I would recommend you to implement <a href="http://recaptcha.net/">reCAPTCHA</a>. Apart from the fact that you can reinitialize a CAPTCHA when you can&#8217;t read it, it has playable sound version of it for visualy impaled people. And on top of all this you help <a href="http://recaptcha.net/learnmore.html">digitize old texts</a>. As if that weren&#8217;t enough, it protects you from bots that may have surpased the other protection techniques.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h2>The math question = ?</h2>
<p>I bet you all have seen it, quite often used in a static equation way. I have also wrote about it on my last home of the blog in the article <a href="http://insanesecurity.wordpress.com/2008/04/22/less-spam-on-blogs/">less spam on blogs</a>. I think that I said enough about it there.</p>
<h2>Javascript to the rescue!?</h2>
<p>It may seem that the simplest and handier way to protect a form against spam bots may as well be Javascript. We live in a web 2.0 enviroument, full of Javascript effects and only a handful of people have it restricted with <a href="http://noscript.net">NoScript</a> or something of sort. Thus we can safely use javascript as a protection against spam. Why? Because normal bots can&#8217;t parse (execute) Javascript code, even crawlers (GoogleBot, YahooBot) parse Javascript code only for obvious links, email addresses, etc.</p>
<p>There are two ways to do a form with Javascript: DOM way and simple dumping way. Simple is better:</p>
<pre>
&lt;form action="target.php"&gt;
  &lt;script type="text/javascript"&gt;
    document.write('&lt;in'+'put type="text" name="human" /&gt;');
    document.write('&lt;inpu'+'t type="submit" /&gt;');
  &lt;/script&gt;
&lt;/form&gt;
</pre>
<p>The concatenation of the strings is needed so that the bots can&#8217;t match it against there usual input regular expressions. I used this type of protection for displaying my email address on the <a href="http://insanesecurity.info/about/">About</a> page, although could have used <a href="http://mailhide.recaptcha.net/">MailHide</a> also. Didn&#8217;t want to bother my readers that much.</p>
<h2>Conclusion</h2>
<p>Actually it&#8217;s totally up to you to choose one of the above. CAPTCHA would be the best, but in some particular cases there is no need to bother your users so much, check my previous example.</p>
<p>Update: <a href="http://www.csarven.ca/hiding-email-addresses">Hide email address in source code</a></p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/spam-free-forms-and-contact-details/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
